前言:
在SpringBoot中,我们可以用@Configuration+@Bean注解完成注入工作,替代了原来的xml管理bean方式。
那么我们来看一下从SpringApplication.run(MyApplication.class, args)到处理@Configuration都涉及到哪些源码。

我们从spring-boot启动类进入源码,自动装配从这里开始
进入run方法

run方法走进来,经过了SpringApplication的构造函数以后,进入上图的run方法。
这个run方法不是今天的重点,所以简单介绍一下。
run方法主要是做环境准备,打印banner,注册Listener等工作。
我们直接进入refreshContext方法。

可以看到跟进来以后,走到了refresh模版方法,这也是spring源码里最关键的一个方法了,spring xml管理bean也是从refresh开始的,所以我们还可以知道,spring-boot最后也是走到refresh去完成升级的。
然后我们直接进入invokeBeanFactoryPostProcessors(beanFactory)方法

再进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

再跟进
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

进入ConfigurationClassPostProcessor实现

然后我们进入processConfigBeanDefinitions(registry);

然后我们进入parser.parse(candidates);

然后我们看三个parse方法,和parse内调用的processConfigurationClass(new ConfigurationClass(reader, beanName));

众所周知Spring源码的风格有一个特点,真正干事情的就是do Prefix Method。
所以我们进入sourceClass = doProcessConfigurationClass(configClass, sourceClass);

有没有发现新大陆,终于看到黄色的Component注解了。
我们继续进入processMemberClasses(configClass, sourceClass);

继续进入ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata())

这里又出现了Bean注解的身影,对的,也就是在这里,Spring完成了@Configuration上下文中所有@Bean实例的metadata信息发现。
最后我们返回上一步
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass)throws IOException
this.importStack.push(configClass);
可以看到类的元信息都保存进了importStack中
再退到public void processConfigBeanDefinitions(BeanDefinitionRegistry registry)中
parser.parse(candidates);
parser.validate();
这两步操作之后

而parser.getImportRegistry返回的正是importStack
ImportRegistrygetImportRegistry() {
return this.importStack;
}
然后我们进入this.reader.loadBeanDefinitions(configClasses);

刚好是从上到下调用的,最后走到了this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
BeanDefinitionRegistry这个类应该是非常熟悉的了,我们经常使用ImportBeanDefinitionRegistrar这个拓展接口主动注入bean,我有一篇博客专门介绍这个的,可以翻一翻。
这里也就完成了beanDefinition的定义了。
所以把上面的串联起来,就是Spring关于自动装配中@Configuration+@Bean组合的实现原理了。
网友评论