大致介绍 SpringFactoriesLoader是 spring 的一个核心类,在 spring-core.jar 包中。它的作用是,用ClassLoader找出项目依赖jar包中的所有“META-INF/spring.factories”文件,将里面的内容加载成 Properties对象(key value对,一个文件加载出一个 Properties),再由 Properties 对象转为 Map<String, List> 格式。 
以下面这个文件为例:
1 2 3 4 5 6 7 8 9 10 11 12 spring-boot-autoconfigure-2.3.0.RELEASE.jar META-INF/spring.factories # Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer 。。。。。 
 
这个文件加载出的 Properties 对象内容有:
1 2 3 4 5 6 7 key1 = "org.springframework.context.ApplicationContextInitializer" value1 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener" key2 = "org.springframework.context.ApplicationListener" value2 = "org.springframework.boot.autoconfigure.BackgroundPreinitializer" 等等 
 
最后转成的 Map<String, List> 格式内容为: 
1 2 3 4 5 6 7 8 key1 = "org.springframework.context.ApplicationContextInitializer" value1List = ["org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer","org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener"] -- 这个 value1List 其实就是把 Properties 对象的 value 保存的字符串按逗号分隔变成的数组 key2 = "org.springframework.context.ApplicationListener" value2List = ["org.springframework.boot.autoconfigure.BackgroundPreinitializer"] 等等 
 
扫描这个“META-INF/spring.factories”文件的目的是什么? SpringBoot 默认会扫描并管理在启动类包路径下的 Bean。如果有想要被扫描但不想改变默认扫描的路径,比如自己写的 jar 包中有 Bean,但不要求使用这个 jar 的应用必须修改默认扫描路径,就在自己 jar 中添加这个“META-INF/spring.factories”文件,将 jar 中的 Bean 的接口与实现类写上,SpringBoot 启动时会在某个阶段?将这些Bean扫描并管理。
 
在哪些路径下寻找spring.factories文件 SpringFactoriesLoader.loadSpringFactories方法中的下面这段代码:
1 2 3 Enumeration<URL> urls = (classLoader != null  ? 		classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : 		ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); 
 
其中 classLoader,即类加载器,是这个方法的入参,可以为null,为null时使用“系统类加载器”,即“应用程序类加载器”,常量 FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”。
这段代码通过调用classLoader.getResources方法返回一个CompoundEnumeration<URL>对象,元素URL中保存的就是某一个“spring.factories”文件所在的绝对路径,如“file:/D:/Development/maven-repo/org/springframework/boot/spring-boot/2.3.0.RELEASE/spring-boot-2.3.0.RELEASE.jar!/META-INF/spring.factories”。但是,在这行代码中还不会得到“spring.factories”文件所在的绝对路径,可以认为这时返回的CompoundEnumeration<URL>对象中的URL元素是空的,它只是获取出会在哪些路径下寻找 URL。
会在哪些路径下寻找 URL 呢?研究ClassLoader.getResources源码就会知道,这些路径就是 启动类加载器+扩展类加载器+应用程序类加载器 3个类加载器负责的路径的并集,即”JVM系统参数sun.boot.class.path” + “JVM系统参数java.ext.dirs” + “环境变量classpath” 包含的路径的并集!也就是说,SpringFactoriesLoader 将会去启动类加载器、扩展类加载器、应用程序类加载器它们3个负责加载的全部路径中,寻找“META-INF/spring.factories”文件,只不过,这个文件一般只存在于应用程序类加载器负责的路径,即“环境变量classpath”指定的路径下。
上面说到,从classLoader.getResources方法返回的变量中还没有找到“spring.factories”文件所在的绝对路径,每个文件的绝对路径是在后面的代码中获取的(代码解释见注释):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private  static  Map<String, List<String>> loadSpringFactories(@Nullable  ClassLoader classLoader) {	 	try  { 		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); 			Properties 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; 	} 	 } 
 
loadFactoryNames 方法 已知loadSpringFactories方法返回的 Map<String, List> result 中,key为接口全限定名,value为“spring.factories”文件中配置的该接口的实现类全限定名。 
loadFactoryNames方法是根据入参Class<?> factoryType指定的 className(接口名),从 loadSpringFactories 方法返回的 Map 中取该接口名对应的实现类名 List。
代码最后的 getOrDefault 意思是如果返回的 Map 中没有指定 key 对应的 value,那么就返回 value=空List,如果有就返回真正的 value。
1 2 3 4 public  static  List<String> loadFactoryNames (Class<?> factoryType, @Nullable ClassLoader classLoader)   {	String factoryTypeName = factoryType.getName(); 	return  loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } 
 
loadFactories 方法 这个方法首先通过loadFactoryNames方法获取指定接口的实现类名 List(变量 factoryImplementationNames),再用instantiateFactory方法根据这些实现类名反射创建 这些实现类的实例对象,如果这些实现类有使用PriorityOrdered或Ordered,还会根据其标注的顺序排序,最后返回排序后的实现类实例对象 List。
排序方法 AnnotationAwareOrderComparator :
 
用于比较的两个对象都实现了 PriorityOrdered 接口,对比它们的 getOrder() 的值,值小的在前 
两个对象中只有一个实现了 PriorityOrdered 接口,则实现了这个接口的排在前 
两个对象中分别查找它们是否实现了Ordered 接口,是则获取 getOrder() 值;若未实现Ordered 接口,就查看它们是否标注了 Order 注解,是则获取注解中的排序值;若也没有 Order 注解,再看是否有 Priority 注解,有则获取注解中的排序值;都没有则返回一个大值,则这个类会被排在后面。排序值小的排在前 
当两个对象排序值相同,会按对象名称排序 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public  static  <T> List<T> loadFactories (Class<T> factoryType, @Nullable ClassLoader classLoader)   {	Assert.notNull(factoryType, "'factoryType' must not be null" ); 	ClassLoader classLoaderToUse = classLoader; 	if  (classLoaderToUse == null ) { 		classLoaderToUse = SpringFactoriesLoader.class .getClassLoader () ; 	} 	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; } private  static  <T> T instantiateFactory (String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader)   {	try  { 		Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader); 		if  (!factoryType.isAssignableFrom(factoryImplementationClass)) { 			throw  new  IllegalArgumentException( 					"Class ["  + factoryImplementationName + "] is not assignable to factory type ["  + factoryType.getName() + "]" ); 		} 		return  (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance(); 	} 	catch  (Throwable ex) { 		throw  new  IllegalArgumentException( 			"Unable to instantiate factory class ["  + factoryImplementationName + "] for factory type ["  + factoryType.getName() + "]" , 			ex); 	} }