SpringFactoriesLoader 是Spring提供的通用的加载 classPath目录下的各个JAR包中的META-INF目录下的 spring.factories 文件的工具,该文件的格式应该符合properties的文件的格式,如果多个值可以通过逗号分割 比如 example.MyService=example.MyServiceImpl1,example.MyServiceImpl2, 全类名为 org.springframework.core.io.support.SpringFactoriesLoader
总结来说,如下:
- 框架内部使用的通用工厂加载机制
- 从ClassPath目录下读取多个JAR报的指定文件
- 文件内容必须是KV,即properties格式
- key是全限定名(抽象类或者接口),value是实现方式, 多个实现,使用逗号分割
其主要流程为:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();// 根据factorynName文件名过滤出Value信息return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}// 查找spring.factories 文件对象信息private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {// 查询目录下的spring.factories 文件路径信息Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);// 构造PropertiesProperties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}}
比如SpringBoot应用获取ApplicationContextInitializer的实例就使用如下的代码:
getSpringFactoriesInstances(ApplicationContextInitializer.class);private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// 获取实现的类限定名Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 实例化对象List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}
