Spring Bean的顺序

之前的文章已经讲过,Spring Bean的创建是通过动态代理实现的,防止浪费篇幅,我们直接看Bean的循环创建代码;

这里我们可以看到 Bean 的创建是通过:

List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
    // Create Bean Code....
}

Bean的创建顺序其实就是this.beanDefinitionNames的顺序。

可以看出this.beanDefinitionNames又是List<?>类型,所以顺序源自add(obj)的顺序。那this.beanDefinitionNames又是怎么填充的呢?

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    // 省略部分代码,直接进入BeanName的add过程.....
    else {
    	if (hasBeanCreationStarted()) {
    		// Cannot modify startup-time collection elements anymore (for stable iteration)
    		synchronized (this.beanDefinitionMap) {
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    			List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    			updatedDefinitions.addAll(this.beanDefinitionNames);
    			updatedDefinitions.add(beanName);
    			this.beanDefinitionNames = updatedDefinitions;
    			removeManualSingletonName(beanName);
    		}
    	}
    	else {
    		// Still in startup registration phase
    		this.beanDefinitionMap.put(beanName, beanDefinition);
    		this.beanDefinitionNames.add(beanName);
    		removeManualSingletonName(beanName);
    	}
    	this.frozenBeanDefinitionNames = null;
    }
    // 省略后续代码...
    
}

再追溯一下org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinitionorg.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod中使用到

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
	TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
	for (ConfigurationClass configClass : configurationModel) {
		loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
	}
}

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
	// 省略....
	for (BeanMethod beanMethod : configClass.getBeanMethods()) {
		loadBeanDefinitionsForBeanMethod(beanMethod);
	}
    // 省略....
}

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    // 省略...
    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
    // 省略...
}

继续向下找到具体的地方:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    // 省略部分代码..
	processConfigBeanDefinitions(registry);
}

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 省略部分代码....    
    // Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
	    this.metadataReaderFactory, this.problemReporter, this.environment,
		this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    do {
        parser.parse(candidates);
        parser.validate();
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);
        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                registry, this.sourceExtractor, this.resourceLoader, this.environment,
                this.importBeanNameGenerator, parser.getImportRegistry());
        }
        this.reader.loadBeanDefinitions(configClasses);
        // 省略部分代码...
    }
    while (!candidates.isEmpty());
    // 省略部分代码...
}

至此,我们基本可以看出来,BeanNames的顺序是由org.springframework.context.annotation.ConfigurationClassPostProcessor决定的,而ConfigurationClassPostProcessor由实现了BeanDefinitionRegistryPostProcessor,其核心就是将代码中注册@Configuration注解的类以及经由此配置类注册的Bean解析为BeanDefinition,而这一步是在refresh()invokeBeanFactoryPostProcessors(beanFactory);完成的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值