SpringFactories加载源码解读
- 概述
- 方法
概述
org.springframework.core.io.support.SpringFactoriesLoader位于spring-core中,是框架内部用于通用工厂类加载的一种机制实现,该类是一个终态类。
通过发现 classpath 下所有jar包中指定的键值对文件(FACTORIES_RESOURCE_LOCATION),该文件必须是以接口或抽象类的全路径为key,值为接口实现或抽象类子类,多各类以逗号分隔。比如example.MyService=example.MyServiceImpl1,example.MyServiceImpl2。
方法
loadFactories(Class factoryType, @Nullable ClassLoader classLoader)
方法描述
通过指定类加载器,加载FACTORIES_RESOURCE_LOCATION中factoryType的实现类并实例化,返回一个经过AnnotationAwareOrderComparator排序的工厂类集合。
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
//获取类加载器sun.misc.Launcher$AppClassLoader
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
//获取factoryType对应的工厂实现类类路径集合
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
//实例工厂实现类,并放到集合中
List<T> result = new ArrayList<>(factoryImplementationNames.size());
for (String factoryImplementationName : factoryImplementationNames) {
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader)
方法描述
调用工厂接口或抽象类加载方法,并获取指定工厂的实现类类路径集合。
代码解读
//通过loadSpringFactories(classLoader)将META-INF/spring.factories解析结果(工厂的实现类)存放到内存缓存中,然后通过工厂接口或抽象类的全路径去获取实现类类路径集合,如果没有则默认返回Collections.emptyList()
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
loadSpringFactories(@Nullable ClassLoader classLoader)
方法描述
通过指定类加载器,解析classpath目录下所有jar包中指定键值对文件中的键值,返回一个map集合。
代码解读
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//先从内存缓存中取,如果有则直接返回
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//查找classpath下对应的META-INF/spring.factories文件,ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)默认通过sun.misc.Launcher$AppClassLoader加载,不存在则查找jdk/jre/lib目录下的jar包
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
//遍历查找到的spring.factories路径集合
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//解析配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
//根据解析结果,以工厂接口或抽象类类路径为key,实现类类路径为值通过集合形式存放到result中
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
//存放到内存缓存中,以当前类模板为key
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
instantiateFactory(String factoryImplementationName,Class factoryType, @Nullable ClassLoader classLoader)
方法描述
通过反射获取类模板,并实例化,返回实例化对象。
代码解读
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
try {
//通过实现类名和类加载器获取类模板
Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
throw new IllegalArgumentException(
"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
}
//通过反射生成类示例
return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
ex);
}
}