BeanDefinition
包含了我们对 Bean 的配置信息,换言之,Spring 将我们对 Bean 的定义信息进行了抽象,抽象后的实体就是 BeanDefinition
,并且Spring 会以此作为标准来创建 Bean 实例
BeanDefinition 创建方式
XmlBeanDefinitionReader 读取
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 基于 XML 资源 BeanDefinitionReader 实现
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String location = "META-INF/beans-context.xml";
// 基于 ClassPath 加载 XML 资源
Resource resource = new ClassPathResource(location);
// 指定字符编码 UTF-8
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(encodedResource);
System.out.println("已加载 BeanDefinition 数量:" + beanNumbers);
// 通过 Bean Id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
}
PropertiesBeanDefinitionReader 读取(这种方式很少用)
public static void main(String[] args) {
// 创建 IoC 底层容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建面向 Properties 资源的 BeanDefinitionReader 示例
PropertiesBeanDefinitionReader beanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);
// Properties 资源加载默认通过 ISO-8859-1,实际存储 UTF-8
ResourceLoader resourceLoader = new DefaultResourceLoader();
// 通过指定的 ClassPath 获取 Resource 对象
Resource resource = resourceLoader.getResource("classpath:/META-INF/user-bean-definitions.properties");
// 转换成带有字符编码 EncodedResource 对象
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
int beanDefinitionsCount = beanDefinitionReader.loadBeanDefinitions(encodedResource);
System.out.println(String.format("已记载 %d 个 BeanDefinition\n", beanDefinitionsCount));
// 通过依赖查找获取 User Bean
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
}
BeanDefinitionBuilder 方式
public static void main(String[] args) {
// 通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 属性设置
beanDefinitionBuilder
.addPropertyValue("id", 1)
.addPropertyValue("name", "wyc1856");
// 获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
}
BeanDefinition 的方法分析
对于每个字段都会有一个对应的方法,只要知道了字段的含义,方法的含义自然就知道了。
// 获取父BeanDefinition,主要用于合并,下节中会详细分析
String getParentName();
// 对于的bean的ClassName
void setBeanClassName(@Nullable String beanClassName);
// Bean的作用域,不考虑web容器,主要两种,单例/原型,见官网中1.5内容
void setScope(@Nullable String scope);
// 是否进行懒加载
void setLazyInit(boolean lazyInit);
// 是否需要等待指定的bean创建完之后再创建
void setDependsOn(@Nullable String... dependsOn);
// 是否作为自动注入的候选对象
void setAutowireCandidate(boolean autowireCandidate);
// 是否作为主选的bean
void setPrimary(boolean primary);
// 创建这个bean的类的名称
void setFactoryBeanName(@Nullable String factoryBeanName);
// 创建这个bean的方法的名称
void setFactoryMethodName(@Nullable String factoryMethodName);
// 构造函数的参数
ConstructorArgumentValues getConstructorArgumentValues();
// setter方法的参数
MutablePropertyValues getPropertyValues();
// 生命周期回调方法,在bean完成属性注入后调用
void setInitMethodName(@Nullable String initMethodName);
// 生命周期回调方法,在bean被销毁时调用
void setDestroyMethodName(@Nullable String destroyMethodName);
// Spring可以对bd设置不同的角色,了解即可,不重要
// 用户定义 int ROLE_APPLICATION = 0;
// 某些复杂的配置 int ROLE_SUPPORT = 1;
// 完全内部使用 int ROLE_INFRASTRUCTURE = 2;
void setRole(int role);
// bean的描述,没有什么实际含义
void setDescription(@Nullable String description);
// 根据scope判断是否是单例
boolean isSingleton();
// 根据scope判断是否是原型
boolean isPrototype();
// 跟合并beanDefinition相关,如果是abstract,说明会被作为一个父beanDefinition,不用提供class属性
boolean isAbstract();
// bean的源描述,没有什么实际含义
String getResourceDescription();
// cglib代理前的BeanDefinition
BeanDefinition getOriginatingBeanDefinition();
BeanDefinition 的继承关系
AbstractBeanDefinition
- 该类作为
BeanDefinition
的通用抽象类,实现了大部分的方法,定义了一系列常量并给很多属性赋了默认值。
ChildBeanDefinition
- 该类在实例化的时候必须要指定一个
parentName
,已经被更加灵活的GenericBeanDefinition
所替代。
GenericBeanDefinition
- 我们通过注解配置的 bean 以及我们的配置类(除
@Bean
以外)的 BeanDefinition 类型都是 GenericBeanDefinition。
RootBeanDefinition
- Spring 在启动时会实例化几个初始化的
BeanDefinition
,这几个BeanDefinition
的类型都为RootBeanDefinition
- Spring 在合并
BeanDefinituon
返回的都是RootBeanDefinition
- 通过
@Bean
注解配置的 bean 解析出来的BeanDefinition
都是RootBeanDefinition
(实际上是其子类ConfigurationClassBeanDefinition
)
AnnotatedGenericBeanDefinition
- 通过
AnnotationConfigRegistry
注册的 bean 都是AnnotatedGenericBeanDefinition
- 通过
@Import
注解导入的类,最后都是解析为AnnotatedGenericBeanDefinition
ScannedGenericBeanDefinition
- 通过注解扫描的类,如
@Service
,@Component
ConfigurationClassBeanDefinition
- 通过
@Bean
注解扫描的类
ClassDerivedBeanDefinition
- 这个类跟
Kotlin
相关,不是太懂
BeanDefinition 的合并
为啥要合并
- 扫描阶段子 BeanDefinition 有些属性数缺失的,需要合并父 BeanDefinition 中的属性
- Spring 本身提供了很多扩展点,在容器启动的时候可能修改 BeanDefinition 的属性,所以每次 getBean的时候需要再合并一次
合并的时机
org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
扫描阶段
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
--> DefaultListableBeanFactory#getBeanNamesForType
实例化阶段
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean