首先看下提供了哪些public方法,还好,只有两个
一长一短选最短,所以先看长的那个loadFactoryNames
/**
* Load the fully qualified class names of factory implementations of the
* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
* class loader.
* <p>As of Spring Framework 5.3, if a particular implementation class name
* is discovered more than once for the given factory type, duplicates will
* be ignored.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @throws IllegalArgumentException if an error occurs while loading factory names
* @see #loadFactories
*/
提取关键信息:
从这里(FACTORIES_RESOURCE_LOCATION)获取指定类型(given type)的实现类名称们(class names of factory implementations),还会去重(duplicates will be ignored)。
因此产生问题:
到底是从哪里?怎么取到的?解答这个问题需要看代码
找到关键方法
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
知道了:是去加载了("META-INF/spring.factories")这个文件,里面定义了key-value形式的信息,value支持多个逗号分隔
2 再看另外一个public方法loadFactories
/**
* Load and instantiate the factory implementations of the given type from
* {@value #FACTORIES_RESOURCE_LOCATION}, using the given class loader.
* <p>The returned factories are sorted through {@link AnnotationAwareOrderComparator}.
* <p>If a custom instantiation strategy is required, use {@link #loadFactoryNames}
* to obtain all registered factory names.
* <p>As of Spring Framework 5.3, if duplicate implementation class names are
* discovered for a given factory type, only one instance of the duplicated
* implementation type will be instantiated.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading (can be {@code null} to use the default)
* @throws IllegalArgumentException if any factory implementation class cannot
* be loaded or if an error occurs while instantiating any factory
* @see #loadFactoryNames
*/
Load and instantiate:好了不用往下看了,加载并实例化。要是不听话再往下看的话,就是说还会排个序。
核心过程是先调用了loadFactoryNames,然后调用instantiateFactory进行实例化