1. 介绍
1.1 为什么使用beanDefinition对spring bean进行建模
由于普通的Class对象无法完成bean的抽象,例如bean的作用域、是否懒加载等,故而需要beanDefinition来抽象这些信息,以便于Spring能完美的实例化一个bean。
1.2 Spring如何实现bean定义
Spring设计了一个BeanDefinition的类用来存储类的类型、名字、构造方法等等。Spring定义了BeanDefinition后置处理器(BeanDefinitionRegistryPostProcessor),而ConfigurationClassPostProcessor实现了该接口。Spring容器启动的时候会去调用ConfigurationClassPostProcessor这个bean工厂的后置处理器完成扫描。故而当Spring读取到类的信息之后会实例化一个BeanDefinition的对象,继而调用这个对象的各种set方法存储bean的基本信息;每扫描到一个符合规则的类,Spring都会实例化一个BeanDefinition对象,然后把根据类的类名生成一个bean的名字(比如一个类IndexService,Spring会根据类名IndexService生成一个bean的名字`indexService`,Spring内部有一套默认的名字生成规则,但是程序员可以提供自己的名字生成器覆盖Spring内置的),继而Spring会把这个beanDefinition对象和生成的beanName放到一个map当中(key=beanName,value=beanDefinition对象),形成映射关系保存起来。
1.2.1 处理ConfigBeanDefinitions
// org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// ...
this.reader.loadBeanDefinitions(configClasses);
// ...
}
1.2.2 注册BeanDefinitions
// org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// ...
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// @Bean 注入的Bean入口在这
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
1.2.3 定义BeanDefinition,然后进行注册
// org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// ...
// 前面都是BeanDefinition的包装
// 这一步是beanName->beanDefinition 映射关系保存至map
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}