通用基础——SpringFactoriesLoader

66 阅读2分钟

首先看下提供了哪些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进行实例化