关联博文:
SpringBoot自动配置原理解析(五)
SpringBoot中如何将@Bean方法解析为BeanDefinition?
接上文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);
关于这两个方法可以参考博文SpringBoot启动流程分析之refresh方法详解