从上一节内容我们知道,要实现延迟加载和分组可以自定义实现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延时加载整体的逻辑了。