BeanDefinition
Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。
不管是是通过xml配置文件的<Bean>标签,还是通过注解配置的@Bean,它最终都会被解析成一个Bean定义信息对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。
从上可知BeanDefinition这个接口对Spring IoC容器的重要之处,所以了解好了它(以及子类),能让我们更大视野的来看Spring管理Bean的一个过程,也能透过现象看本质。
比喻
- Spring IoC容器好比一间餐馆
当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。IoC容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。 - BeanDefinition就是做菜的原料
容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的 所有 必要信息,包括bean对象的beanClass、scope、lazyInit类属性、是否是抽象类、构造方法和参数、其它属性等等(所以BeanDefinition就好比做菜的原料) - BeanDefinitionRegistry和 BeanFactory就是菜谱
BeanDefinitionRegistry抽象出bean的注册逻辑,而BeanFactory则抽象出了bean的管理逻辑。 各个BeanFactory的实现类就具体承担了bean的注册以及管理工作。
BeanDefinition源码
源码如下:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 单例Bean还是原型Bean
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// Bean角色
int ROLE_APPLICATION = 0; //应用程序重要组成部分
int ROLE_SUPPORT = 1; //做为大量配置的一部分(支持、扩展类) 实际上就是说,我这个Bean是用户的,是从配置文件中过来的。
int ROLE_INFRASTRUCTURE = 2; //指内部工作的基础构造 实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系
// Modifiable attributes
//parent definition(若存在父类的话,就设置进去)
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
// 指定Class类型。需要注意的是该类型还有可能被改变在Bean post-processing阶段
// 若是getFactoryBeanName getFactoryMethodName这种情况下会改变
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
//SCOPE_SINGLETON或者SCOPE_PROTOTYPE两种
void setScope(@Nullable String scope);
@Nullable
String getScope();
// @Lazy 是否需要懒加载(默认都是立马加载的)
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 此Bean定义需要依赖的Bean(显然可以有多个)
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
// 这个Bean是否允许被自动注入到别的地方去(默认都是被允许的)
// 注意:此标志只影响按类型装配,不影响byName的注入方式的~~~~
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 是否是首选的 @Primary
void setPrimary(boolean primary);
boolean isPrimary();
// 指定使用的工厂Bean(若存在)的名称~
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
//指定工厂方法~
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
// 获取此Bean的构造函数参数值们 ConstructorArgumentValues:持有构造函数们的
// 绝大多数情况下是空对象 new ConstructorArgumentValues出来的一个对象
// 当我们Scan实例化Bean的时候,可能用到它的非空构造,这里就会有对应的值了,然后后面就会再依赖注入了
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// 获取普通属性集合~~~~
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// Read-only attributes
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
// 对应上面的role的值
int getRole();
//@Description
@Nullable
String getDescription();
// 返回该Bean定义来自于的资源的描述(用于在出现错误时显示上下文)
@Nullable
String getResourceDescription();
//返回原始BeanDefinition,如果没有则返回@null
// 若这个Bean定义被代理、修饰过 这个方法可以返回原始的
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
具体实现类
-
AbstractBeanDefinition
AbstractBeanDefinition实现了BeanDefinition定义的一系列操作,定义了描述Bean画像的一系列属性,在AbstractBeanDefinition的基础上,Spring衍生出了一系列具有特殊用途的BeanDefinition。 -
GenericBeanDefinition
标准通用的beanDefinition。除了具有指定类、可选的构造参数值和属性参数这些其它beanDefinition一样的特性外,它还具有通过parenetName属性来动态设置parent bean definition。 -
ChildBeanDefinition
子Bean定义信息,依赖于父类RootBeanDefinition
ChildBeanDefinition是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinition对RootBeanDefinition有一定的依赖关系。 -
RootBeanDefinition
一个RootBeanDefinition定义表明它是一个可合并的beanDefinition:即在spring beanFactory运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用GenericBeanDefinition来做。
在 配置文件中可以定义父和子,父用RootBeanDefinition表示, 而子用ChildBeanDefiniton表示,而没有父的就使用 RootBeanDefinition表示。 -
子接口:AnnotatedBeanDefinition
增加了一个注解元数据AnnotationMetadata取得方法。
AnnotatedBeanDefinition的三个子类:
1.ScannedGenericBeanDefinition
存储@Component、@Service、@Controller等注解注释的类
它的源码很简单,就是多了一个AnnotationMetadata 属性,用来存储一些注解信息。
2. AnnotatedGenericBeanDefinition
在基于注解驱动的Spring应用着,它使用得非常的多。因为获取注解信息非常的方便。
AnnotatedGenericBeanDefinition只能用于已经被注册或被扫描到的类。
3.ConfigurationClassBeanDefinition
首先需要注意的是,它是ConfigurationClassBeanDefinitionReader的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类。
ConfigurationClassBeanDefinition直接继承自RootBeanDefinition
它有一些默认的设置处理如下:
@Bean注解没有指定bean的名字,默认会用方法的名字命名bean
@Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化(所以我们方法体里面可以很方便的书写逻辑。)