【springboot源码解读系列】(五、springboot启动之解析META-INF/spring.factories的SpringFactoriesLoader详细解读)

上一讲【springboot源码解读系列】(四、springboot启动之SpringApplicationRunListeners:通知所有监听器,系统启动中…用于非常早的初始化)说到通过SpringFactoriesLoader加载META-INF/spring.factories获取我们的自定义监听器和启动器。

那么这讲就来揭开SpringFactoriesLoader神秘的面纱:讲解都在注释里面:

值得学习的是他的这种设计理念,通过指定规范,然后对其使用者提供扩展,springboot的启动器原理也是这样来进行实现的。

精华提取:ConcurrentMap(线程安全的map集合)作为缓存cache、通过构造器去创建实例(accessibleConstructor)、isAssignableFrom判断是否是其子类(isAssignableFrom和instanceof关键字的区别)

package org.springframework.core.io.support;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.UrlResource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

/**
 * 通用工厂加载机制实现的内部使用框架。spring内部使用的
 *
 * springfactoresloader会加载META-INF/spring.factories文件中给定类型的工厂,
 * 为什么是工厂,因为一个key可以对应多个value,
 * spring.factories的文件类型是properties格式的,其中键是完全限定的接口或抽象类的名称,值是以逗号分隔的
 *
 * 比如:
 * 
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
* */
public final class SpringFactoriesLoader { /** * 本地的工厂文件, * 可以存在于多个jar中,也就是他会扫码所有的jar,然后解析所有的META-INF/spring.factories文件, * 并将其配置的创建其工厂,以及对所有value进行实例化 */ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; // 日志框架 private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class); // 定义一个map,其中key为ClassLoader,value为MultiValueMap // MultiValueMap集成自Map // ConcurrentReferenceHashMap集成自ConcurrentMap,也就是一个线程安全的map private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>(); // 空参构造函数 private SpringFactoriesLoader() { } /** * 通过classLoader从各个jar包的classpath下面的META-INF/spring.factories加载并解析其key-value值,然后创建其给定类型的工厂实现 * * 返回的工厂通过AnnotationAwareOrderComparator进行排序过的。 * AnnotationAwareOrderComparator就是通过@Order注解上面的值进行排序的,值越高,则排的越靠后 * * 如果需要自定义实例化策略,请使用loadFactoryNames方法获取所有注册工厂名称。 * * @param factoryType 接口或者抽象类的Class对象 * @param classLoader 用于加载的类加载器(可以是null,如果是null,则使用默认值) * @throws IllegalArgumentException 如果无法加载任何工厂实现类,或者在实例化任何工厂时发生错误,则会抛出IllegalArgumentException异常 */ public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) { // 首先断言,传入的接口或者抽象类的Class对象不能为空 Assert.notNull(factoryType, "'factoryType' must not be null"); // 将传入的classLoader赋值给classLoaderToUse // 判断classLoaderToUse是否为空,如果为空,则使用默认的SpringFactoriesLoader的classLoader ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } // 加载所有的META-INF/spring.factories并解析,获取其配置的factoryNames List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse); if (logger.isTraceEnabled()) { logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames); } List<T> result = new ArrayList<>(factoryImplementationNames.size()); // 通过反射对所有的配置进行实例化。 for (String factoryImplementationName : factoryImplementationNames) { result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse)); } AnnotationAwareOrderComparator.sort(result); return result; } /** * 使用给定的类加载器从META-INF/spring.factories加载给定类型的工厂实现的完全限定类名。 * @param factoryType 接口或者抽象类的Class对象 * * @param classLoader classLoader 用于加载的类加载器(可以是null,如果是null,则使用默认值) * * @throws IllegalArgumentException 如果在加载工厂名称时发生错误 * @see #loadFactories */ public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { // 通过Class对象获取全限定类名 String factoryTypeName = factoryType.getName(); // loadSpringFactories方法是获取所有的springFactories // getOrDefault是通过key,获取到对应的类的集合。因为value是通过逗号相隔的,可以有多个,所以是list // getOrDefault如果存在就返回,如果不存在那么就返回给的默认值 return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } // 加载所有的springFactories private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { // 首先从cache中获取,根据classLoader, // cache是以ClassLoader作为key的。是静态的final修饰的。整个应用只有一份 MultiValueMap<String, String> result = cache.get(classLoader); // 如果为null,证明还没有加载过,如果不为空,那么就添加。 if (result != null) { return result; } try { // 三目表达式,判断参数classLoader是否为空,如果不为空,那么直接使用传入的classLoader获取META-INF/spring.factories // 如果为空,那么就使用系统的classLoader来获取META-INF/spring.factories // 总之健壮性比较强, Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { // 通过循环遍历所有的META-INF/spring.factories URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); // 解析properties Properties properties = PropertiesLoaderUtils.loadProperties(resource); // 将所有的key放入result 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); } } // 实例化工厂,根据 @SuppressWarnings("unchecked") private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) { try { // 根据全限定类名通过反射获取Class对象 Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader); // 判断获取的Class对象是否从factoryType里面来, // 说具体点就是判断我们配置的spring.factories中的权限定类名所对应的类是否是对应的子类或者实现类 // 比如 // org.springframework.context.ApplicationContextInitializer=\ // org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ // org.springframework.boot.context.ContextIdApplicationContextInitializer, // 那么他就会验证ConfigurationWarningsApplicationContextInitializer和ContextIdApplicationContextInitializer是否是ApplicationContextInitializer的子类 // isAssignableFrom()方法与instanceof关键字的区别总结为以下两个点: // isAssignableFrom()方法是从类继承的角度去判断,instanceof关键字是从实例继承的角度去判断。 // isAssignableFrom()方法是判断是否为某个类的父类,instanceof关键字是判断是否某个类的子类。 // 如果不是,则会保存 if (!factoryType.isAssignableFrom(factoryImplementationClass)) { throw new IllegalArgumentException( "Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]"); } // 通过反射的有参构造函数进行实例化:如果直接newInstance的话,那么只能通过空参构造函数进行实例化。 // 通过这种方式可以通过不同参数的构造函数进行创建实例,但是这里并没有传入参数,所以调用的是默认空惨构造函数 return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance(); } catch (Throwable ex) { throw new IllegalArgumentException( "Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]", ex); } } }

你可能感兴趣的:(Springboot,源码,spring,boot)