精尽 Spring Boot 源码分析 —— SpringFactoriesLoader
1. 概述
本文,我们来补充 《精尽 Spring Boot 源码分析 —— SpringApplication》 文章,并未详细解析的 SpringFactoriesLoader 。
艿艿:如果对 Java SPI 不了解的胖友,推荐后面看看 《JAVA 拾遗 —— 关于 SPI 机制》 文章。
2. SpringFactoriesLoader
org.springframework.core.io.support.SpringFactoriesLoader ,加载 spring.factories 的工具类。其类上,注释如下:
// SpringFactoriesLoader.java/*** General purpose factory loading mechanism for internal use within the framework.** <p>{@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:** <pre class="code">example.MyService=example.MyServiceImpl1,example.MyServiceImpl2</pre>** 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.* <p>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<ClassLoader, MultiValueMap<String, String>> 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<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {// 获得接口的类名String factoryClassName = factoryClass.getName();// 加载 FACTORIES_RESOURCE_LOCATION 配置文件,获得接口对应的实现类名们return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {// 如果缓存中已经存在,则直接返回MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {// 获得 FACTORIES_RESOURCE_LOCATION 对应的 URL 们Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));// 创建 LinkedMultiValueMap 对象result = new LinkedMultiValueMap<>();// 遍历 URL 数组while (urls.hasMoreElements()) {// 获得 URLURL 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<String> 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<T> 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.* <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.* @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 <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {Assert.notNull(factoryClass, "'factoryClass' must not be null");// 获得 ClassLoaderClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}// 获得接口对应的实现类名们List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);if (logger.isTraceEnabled()) {logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);}// 遍历 factoryNames 数组,创建实现类的对象List<T> result = new ArrayList<>(factoryNames.size());for (String factoryName : factoryNames) {result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));}// 排序AnnotationAwareOrderComparator.sort(result);return result;
}private static <T> T instantiateFactory(String instanceClassName, Class<T> 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. 彩蛋
水文一篇,哇咔咔~