META-INF spring.factories

为什么80%的码农都做不了架构师?>>>   hot3.png

spring boot 如何加载META-INF/spring.factories,依赖spring-boot版本为[2.0.2.RELEASE]

通过main主入口,加载SpringApplication,源码如下:

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 = deduceWebApplicationType();
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

通过上面,可以提取以下几点信息:

  • 应用类型 deduceWebApplicationType 识别
  • setInitializers 初始化
  • setListeners 初始化
  • deduceMainApplicationClass 主入口识别

由于本次主要介绍META-INF/spring.factories解析,下面任意将逐步进行阅读

  • 第一步
setInitializers((Collection) getSpringFactoriesInstances(
		ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  • 第二步
private  Collection getSpringFactoriesInstances(Class type,
		Class[] parameterTypes, Object... args) {
	ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set names = new LinkedHashSet<>(
			SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List instances = createSpringFactoriesInstances(type, parameterTypes,
			classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}
  • 第三步重点解析,根据传入Class类型进行全包扫描是否包含 META-INF/spring.factories文件
Set names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
	MultiValueMap result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	try {
		Enumeration 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()) {
				List factoryClassNames = Arrays.asList(
						StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
				result.addAll((String) entry.getKey(), factoryClassNames);
			}
		}
		cache.put(classLoader, result);
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

第四步,你可以选择debug,假如当前pom中只依赖spring-boot-starter,展开依赖包你将看到配置META-INF/spring.factories 目录的jar包有spring-boot、spring-boot-autoconfigure、spring-bean 等三个项目包,


    
        org.springframework.boot
        spring-boot-starter
    

第五步,以[ApplicationContextInitializer] 为例,你将看到分别在spring-boot、spring-boot-autoconfigure中发现

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

第六步,最终你将看到names set集合中包含了上面6个实现类,在下面具体代码中进行实例化和排序

private  Collection getSpringFactoriesInstances(Class type,
			Class[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

end

转载于:https://my.oschina.net/kcnf/blog/2986541

你可能感兴趣的:(META-INF spring.factories)