Spring boot源码分析(一) bootstrapRegistryInitializers & setInitializers

2021/7/19 20:38:24

本文主要是介绍Spring boot源码分析(一) bootstrapRegistryInitializers & setInitializers,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

看了很多关于spring boot 的源码分析,感觉都只在关注面试题, 关键注解,但是这样并无法达到对其启动的深刻理解,只是死板的记忆,,过了几天又忘了 ,所以我在看完之后打算把他记下来,以供以后复习使用。重点是一定要自己点一遍

1. 核心注解SpringBootApplication
@SpringBootConfiguration – 配置类 就是@Configuration
@EnableAutoConfiguration – 核心注解,通过@import + @Configuration + @Bean 导入第三方jar
@ComponentScan – 包扫描,默认扫当前启动类所在包一下的所有注解 ,将其加入IOC
2. 启动类SpringApplication.run()

new SpringApplication(primarySources).run(args);
启动类Run方法可以分为两部分
new SpringApplication(primarySources)
run(args);方法
  1. 第一部分new SpringApplication(primarySources)
    primarySources == HelloworldApplication.class 启动类 类型
@SpringBootApplication
public class HelloworldApplication {

	public static void main(String[] args) {
		SpringApplication.run(HelloworldApplication.class, args);
	}

}

进入启动类

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

重点 分析三句:

this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

1.1 getBootstrapRegistryInitializersFromSpringFactories()

	private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
		ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
		getSpringFactoriesInstances(Bootstrapper.class).stream()
				.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
				.forEach(initializers::add);
		initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		return initializers;
	}

核心方法: getSpringFactoriesInstances()

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	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);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

SpringFactoriesLoader.loadFactoryNames()
通过classloader 的双亲委派机制加载所有jar中的META-INF/spring.factories文件
并将其读取存入cache中以便下次取用。

 	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

其中存储的是spring 启动中重要的类及其对应子类
在启动中接下来药用到的就是ApplicationContextInitializer 和 ApplicationListener , 最重要的还有EnableAutoConfiguration , 可以看到他又130个子类(后面再说)在这里插入图片描述
当他初始化好之后,会进行一个过滤
loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
获取当前传入class的配置,当前是Bootstrapper.class , 但是在配置文件中并没有他的配置。所以instance最终为0
在这里插入图片描述
最后返回到最外层getBootstrapRegistryInitializersFromSpringFactories
此时bootstrapRegistryInitializers还没有值(size为0)
1.2 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
同样的逻辑,这次会取出所有ApplicationContextInitializer.class的子类
在这里插入图片描述
随后通过createSpringFactoriesInstances , 为所有的子类创建一个空的实例
在这里插入图片描述

  1. 第二部分run(args);方法


这篇关于Spring boot源码分析(一) bootstrapRegistryInitializers & setInitializers的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程