SpringBoot快速入门-SpringBoot延时加载原理

从上一节内容我们知道,要实现延迟加载和分组可以自定义实现DeffredImportSelector接口,但是它的原理是什么呢?我们来看一下源码。
从我们应用主函数的run方法进入

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

依次进入run方法

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return (new SpringApplication(primarySources)).run(args);
}

然后进入到run(String… args)方法

public ConfigurableApplicationContext run(String... args) {
	......
}

这个run方法有一行this.refreshContext(context) 点击进入

private void refreshContext(ConfigurableApplicationContext context) {
	if (this.registerShutdownHook) {
		shutdownHook.registerApplicationContext(context);
	}

	this.refresh(context);
}
继续进入this.refresh(context),进入的是AbstractApplicationContext类的的refresh方法
继续进入invokeBeanFactoryPostProcessors(beanFactory)方法
继续进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法
继续进入invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup())方法
继续进入ConfigurationClassPostProcessor类的postProcessor.postProcessBeanDefinitionRegistry(registry)方法
继续进入processConfigBeanDefinitions(registry)方法
继续进入parser.parse(candidates)方法

这里就是重点了

public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
	BeanDefinition bd = holder.getBeanDefinition();
	try {
		if (bd instanceof AnnotatedBeanDefinition) {
			parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
		}
		else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
			parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
		}
		else {
			parse(bd.getBeanClassName(), holder.getBeanName());
		}
	}
	catch (BeanDefinitionStoreException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanDefinitionStoreException(
				"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
	}
}

this.deferredImportSelectorHandler.process();
}

这里的for循环就是加载各种配置类、注册类的逻辑代码,并且在这些代码执行过程中,发现如果有deferredImportSelector接口实现的类,那么就加到deferredImportSelectorHandler集合中,等到其余配置类加载完之后,在这个方法最后一行才开始执行延迟加载的类,也就是这一行代码this.deferredImportSelectorHandler.process()。

继续进入this.deferredImportSelectorHandler.process()方法

public void process() {
	List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
	this.deferredImportSelectors = null;
	try {
		if (deferredImports != null) {
			DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
			deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
			deferredImports.forEach(handler::register);
			handler.processGroupImports();
		}
	}
	finally {
		this.deferredImportSelectors = new ArrayList<>();
	}
}

如果延迟加载的集合不为空,那么就开始执行handler.processGroupImports()方法
继续进入grouping.getImports()

public Iterable<Group.Entry> getImports() {
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	return this.group.selectImports();
}

这里就是上一节实践讲到的,如果getImportGroup方法不为空则调用先执行getImportGroup,就不再执行selectImport方法了。

以上这些就是SpringBoot延时加载整体的逻辑了。