spring spi源码
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.factoriesEnumeration<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中。