接上文SpringBoot自动配置原理解析(三)后,我们本文开始分析this.reader.loadBeanDefinitions(configClasses);
。也就是ConfigurationClassBeanDefinitionReader
的loadBeanDefinitions
方法。
也就是在这个方法里面,对前面没有处理的@Bean注解的method
、配置类引入的 比如AutoConfigurationPackages.Registrar
以及扫描得到的XXXXAutoConfiguration做了处理。
【1】ConfigurationClassBeanDefinitionReader
如下所示,首先实例化一个TrackedConditionEvaluator
,然后对每个ConfigurationClass
执行loadBeanDefinitionsForConfigurationClass
方法。
// ConfigurationClassBeanDefinitionReader
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
① loadBeanDefinitionsForConfigurationClass
loadBeanDefinitionsForConfigurationClass方法如下所示:
// ConfigurationClassBeanDefinitionReader
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//判断是否跳过当前configClass,如果跳过则从registry importRegistry移除数据
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 如果当前类是通过@Import导入或者是某个配置类的内部类或者扫描得到的XXXAutoConfiguration
if (configClass.isImported()) {
// 注册configClass自身作为一个BeanDefinition放到beanDefinitionMap中
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 遍历配置类持有的BeanMethod,注册BeanDefinition到beanDefinitionMap中
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//获取配置类持有的importedResources,解析配置文件加载BeanDefinition
//如果你使用了@ImportResource(locations = {"classpath:beans.xml"}),这里就会解析beans.xml文件
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//获取配置类持有的importBeanDefinitionRegistrars,触发其registerBeanDefinitions方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
梳理逻辑如下:
- 判断是否跳过当前configClass,如果跳过则从registry importRegistry移除数据
- 如果当前类是通过@Import导入或者是某个配置类的内部类或者是spring.factories扫描得到的xxxAutoConfiguration,则注册configClass自身作为一个BeanDefinition放到beanDefinitionMap中
- 遍历配置类持有的BeanMethod,注册BeanDefinition到beanDefinitionMap中
- 获取配置类持有的importedResources,解析配置文件加载BeanDefinition。如果你使用了
@ImportResource(locations = {"classpath:beans.xml"})
,这里就会解析beans.xml文件 - 获取配置类持有的importBeanDefinitionRegistrars,触发其registerBeanDefinitions方法
② loadBeanDefinitionsFromRegistrars
loadBeanDefinitionsFromRegistrars
方法如下所示,对每一个Entry触发registrar的registerBeanDefinitions
方法。
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
我们以AutoConfigurationPackages.Registrar为例,这里会来到registerBeanDefinitions方法。
我们继续往下看AutoConfigurationPackages的register方法,本文这里只是实例化得到一个GenericBeanDefinition 并注册到registry中。
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
如下图所示,注册的beanName与beanDefinition。
也就是说这个方法以编程方式注册自动配置包名称。您可以使用此方法手动定义将用于给定BeanDefinitionRegistry的基本包。通常,建议不要直接调用此方法,而是依赖默认约定,其中包名是从@EnableAutoConfiguration
配置类设置的。
【2】bean的实例化
如下所示,当我们do…while执行完毕后,我们有了442个BeanDefinition。
这些BeanDefinition在什么时候实例化呢?大部分在如下两个方法中:
//实例化BeanPostProcessor
registerBeanPostProcessors(beanFactory);
//实例化非懒加载的单例
finishBeanFactoryInitialization(beanFactory);