Skip to content

Latest commit

 

History

History
186 lines (145 loc) · 6.81 KB

(3)工厂加载机制解析.md

File metadata and controls

186 lines (145 loc) · 6.81 KB

工厂加载机制解析

SpringFactoriesLoader 介绍

org.springframework.core.io.support.SpringFactoriesLoader

/**
 * General purpose factory loading mechanism for internal use within the framework.
 *
 * <p>{@code SpringFactoriesLoader} {@linkplain #loadFactories loads} and instantiates
 * factories of a given type from {@value #FACTORIES_RESOURCE_LOCATION} files which
 * may be present in multiple JAR files in the classpath. The {@code spring.factories}
 * file must be in {@link Properties} format, where the key is the fully qualified
 * name of the interface or abstract class, and the value is a comma-separated list of
 * implementation class names. For example:
 *
 * <pre class="code">example.MyService=example.MyServiceImpl1,example.MyServiceImpl2</pre>
 *
 * where {@code example.MyService} is the name of the interface, and {@code MyServiceImpl1}
 * and {@code MyServiceImpl2} are two implementations.
 *
 * @author Arjen Poutsma
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @since 3.2
 */
public final class SpringFactoriesLoader {
  • 框架内部使用的通用工厂加载机制
  • 从classpath 下多个jar包特定的位置读取文件并初始化类
  • 文件内容必须是kv形式,即properties类型
  • key是全限定名(抽象类|接口)、value是实现,多个实现用逗号分隔

框架初始化步骤

image-20210616203348022

源码阅读

1、首先通过setInitializers#()方法设置系统初始化器
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 通过setInitializers#()方法,设置系统初始化器
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
2、获取系统初始化器实现的全路径名,为它们创建实例子,最终把它们进行排序后注入到Spring容器集合中
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    // 获得类加载器
		ClassLoader classLoader = getClassLoader();
    // 通过这个SpringFactoriesLoader#loadFactoryNames方法获取Spring中所有系统初始化器实现的全路径名
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // #()创建它们的实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 通过注解@Order进行排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
3、获取系统初始化器实现的全路径名
	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 ?
				  // 获取 META-INF/spring.factories下所有系统初始化器的实现                               
					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);
        // 通过url路径,获取spring.factories中的配置,并将其转成Properties格式
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
            // 将初始化器的包名进行返回
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
      // 记录到缓存中
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}
4、创建初始化器的实例
	@SuppressWarnings("unchecked")
	private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
        // 通过反射获取具体实现,并完成类的初始化,最终返回实现类的实例
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}
5、按@Order注解进行排序
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 按@Order注解进行排序,值约小的越靠前
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
6、将初始化器排序好的实例注册到Spring容器中
	public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<>();
    // 将初始化器的实例添加到Spring容器中
		this.initializers.addAll(initializers);
	}

总结

  • SpringFactoriesLoader作用: SpringBoot框架中从类路径jar包中读取特定的文件(META-INF/spring.factories)实现扩展类的载入

image-20210726172128392

  • LoadFactories流程

image-20210726172754618