# 精尽 Spring Boot 源码分析 —— SpringFactoriesLoader # 1. 概述 本文,我们来补充 [《精尽 Spring Boot 源码分析 —— SpringApplication》](http://svip.iocoder.cn/Spring-Boot/SpringApplication) 文章,并未详细解析的 SpringFactoriesLoader 。 - `spring.factories` 配置文件,我们可以认为是 Spring 自己的一套 SPI 机制的配置文件,在里面可以配置不同接口对应的实现类**们**。例如: ``` # PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener // ... 省略其它 ``` - 并且,Spring 内置了多个 `spring.factories` 配置文件。另外,我们也可以添加 `spring.factories` 配置文件。 - SpringFactoriesLoader 类,用于加载 `spring.factories` 配置文件。 > 艿艿:如果对 Java SPI 不了解的胖友,推荐后面看看 [《JAVA 拾遗 —— 关于 SPI 机制》](http://www.iocoder.cn/Fight/xuma/spi/?vip) 文章。 # 2. SpringFactoriesLoader `org.springframework.core.io.support.SpringFactoriesLoader` ,加载 `spring.factories` 的工具类。其类上,注释如下: ``` // SpringFactoriesLoader.java /** * General purpose factory loading mechanism for internal use within the framework. * *

{@code SpringFactoriesLoader} {@linkplain #loadFactories loads} and instantiates * factories of a given type from {@value #FACTORIES_RESOURCE_LOCATION} files which * may be present in multiple JAR files in the classpath. The {@code spring.factories} * file must be in {@link Properties} format, where the key is the fully qualified * name of the interface or abstract class, and the value is a comma-separated list of * implementation class names. For example: * *

example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
* * where {@code example.MyService} is the name of the interface, and {@code MyServiceImpl1} * and {@code MyServiceImpl2} are two implementations. */ ``` 从包名我们就可以看出,SpringFactoriesLoader 是 Spring Framework 就已经提供的工具类,😈 而不是 Spring Boot 所特有的。 ## 2.1 构造方法 ``` // SpringFactoriesLoader.java /** * The location to look for factories. *

Can be present in multiple JAR files. */ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class); /** * 缓存 * * KEY1 :ClassLoader * KEY2 :接口的类名 * VALUE :实现的类名的数组。注意哟,是个 MultiValueMap 类 */ private static final Map> cache = new ConcurrentReferenceHashMap<>(); private SpringFactoriesLoader() { } ``` - `FACTORIES_RESOURCE_LOCATION` 静态属性,定义了读取的是 `"META-INF/spring.factories"` 配置文件。并且,每个 JAR 文件里,都可以有一个这个配置文件。 - `cache` 静态属性,读取 `"META-INF/spring.factories"` 配置文件的缓存。 ## 2.2 loadFactoryNames `#loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader)` 静态方法,获得接口对应的实现类名们。代码如下: ``` // SpringFactoriesLoader.java /** * Load the fully qualified class names of factory implementations of the * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given * class loader. * @param factoryClass 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 */ public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) { // 获得接口的类名 String factoryClassName = factoryClass.getName(); // 加载 FACTORIES_RESOURCE_LOCATION 配置文件,获得接口对应的实现类名们 return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) { // 如果缓存中已经存在,则直接返回 MultiValueMap result = cache.get(classLoader); if (result != null) { return result; } try { // 获得 FACTORIES_RESOURCE_LOCATION 对应的 URL 们 Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); // 创建 LinkedMultiValueMap 对象 result = new LinkedMultiValueMap<>(); // 遍历 URL 数组 while (urls.hasMoreElements()) { // 获得 URL URL url = urls.nextElement(); // 创建 UrlResource 对象 UrlResource resource = new UrlResource(url); // 加载 "META-INF/spring.factories" 配置文件,成为 Properties 对象 Properties properties = PropertiesLoaderUtils.loadProperties(resource); // 遍历 Properties 对象 for (Map.Entry entry : properties.entrySet()) { // 使用逗号分隔 List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); // 添加到 result 中 result.addAll((String) entry.getKey(), factoryClassNames); } } // 添加到 cache 中 cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } ``` - 加载 `FACTORIES_RESOURCE_LOCATION` 配置文件,获得接口对应的实现类名们。 ## 2.3 loadFactories `#loadFactories(Class factoryClass, @Nullable ClassLoader classLoader)` **静态**方法,获得接口对应的实现类名们,然后创建对应的对象们。代码如下: ``` // SpringFactoriesLoader.java /** * Load and instantiate the factory implementations of the given type from * {@value #FACTORIES_RESOURCE_LOCATION}, using the given class loader. *

The returned factories are sorted through {@link AnnotationAwareOrderComparator}. *

If a custom instantiation strategy is required, use {@link #loadFactoryNames} * to obtain all registered factory names. * @param factoryClass 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 */ public static List loadFactories(Class factoryClass, @Nullable ClassLoader classLoader) { Assert.notNull(factoryClass, "'factoryClass' must not be null"); // 获得 ClassLoader ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } // 获得接口对应的实现类名们 List factoryNames = loadFactoryNames(factoryClass, classLoaderToUse); if (logger.isTraceEnabled()) { logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames); } // 遍历 factoryNames 数组,创建实现类的对象 List result = new ArrayList<>(factoryNames.size()); for (String factoryName : factoryNames) { result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse)); } // 排序 AnnotationAwareOrderComparator.sort(result); return result; } private static T instantiateFactory(String instanceClassName, Class factoryClass, ClassLoader classLoader) { try { // 获得 Class 类 Class instanceClass = ClassUtils.forName(instanceClassName, classLoader); // 判断是否实现了指定接口 if (!factoryClass.isAssignableFrom(instanceClass)) { throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]"); } // 创建对象 return (T) ReflectionUtils.accessibleConstructor(instanceClass).newInstance(); } catch (Throwable ex) { throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), ex); } } ``` # 666. 彩蛋 水文一篇,哇咔咔~