文章目录
前言
本文所涉及spring/spring boot代码,请参考spring boot 2.2.6对应版本。
我们在刚学习spring boot时,有没有一个困惑:spring boot能够自动实例化很多第三方的依赖库?比如eureka、druid等。这个就涉及到spring boot的扩展机制spring factories。
简单来讲,spring factories类似与Java SPI机制,利用该机制,我们能够自定义实现一些SDK或是spring boot starter,其实例化过程由我们来实现,使用方只需要在项目中引入包、不需要或是只需做很少的配置。
Spring Factories的核心
spring factories机制核心在spring-core包中定义的SpringFactoriesLoader类,该类的公有方法只有2个:
/*
根据接口类获取其实现类的实例,这个方法返回的是对象列表。
Load and instantiate the factory implementations of the given type from "META-INF/spring.factories", using the given class loader.
The returned factories are sorted through AnnotationAwareOrderComparator.
If a custom instantiation strategy is required, use loadFactoryNames(java.lang.Class<?>, java.lang.ClassLoader) to obtain all registered factory names.
*/
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader)
/*
根据接口获取其接口类的名称,这个方法返回的是类名的列表。
Load the fully qualified class names of factory implementations of the given type from "META-INF/spring.factories", using the given class loader.
*/
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)
而上面这两个方法,最终都会调用一个SpringFactoriesLoader的私有方法loadSpringFactories,从指定的ClassLoader中获取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 {
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<