spring spi是啥
spring spi机制是spring实现自动装配的基础机制。
spi源码
public final class SpringFactoriesLoader{
// 指定读取路径
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 用来缓存的容器
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 取缓存or加载解析
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 利用类加载器加载所有的spring.factories
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 逐个解析
while (urls.hasMoreElements()) {
// 提取每个spring.factories文件
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 读取spring.factories文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
// 逐个收集映射
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
// 如果一个key有多个value,则用英文逗号隔开,在这里做分隔
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);
}
}
}
逻辑简述
spi第一次执行时会通过类加载器读取指定路径的文件。这个文件其实就是spring的properties文件。
第一次读取后,会用ConcurrentReferenceHashMap进行缓存。
每个spring.factories文件都会被当作一个Properties对象进行解析,可以提取每一对映射关系,最终存到Map中。