背景简介
本文主要对 BeanDefinition
接口进行简单的介绍。
出现的原因
在 Spring 工作时,明显的分成两个阶段:
- 从配置中读取信息,并生成此项目对应的 Bean 的定义,缓存在内存中。
- 用户【可能是人也可能是应用程序、应用框架】根据需要指示 Spring 生成指定的 bean 实例。
所以需要一个至关重要的数据结构,来缓存从配置中读取的 Bean 的定义。
职责
缓存创建 Bean 所需的一切信息。
BeanDefinition
主要指责如下:
- 对 Bean 的创建的所有可能用到的字段进行了存取方法的定义
- 对 Bean 的创建中可能用到的一些常量进行了定义
注意:既然是对从配置中读取的信息的处理结果,考虑到很多依赖于 Spring 的框架的扩展问题。 BeanDefinition
还对生成自己的配置做了一个保存,方便用户进行自行定制。【此处有一些想法,参见"想法——程序员的思维"】
源码
继承关系
根据上面的职责大概能猜到,BeanDefinition
中就是一些getter/setter
方法、一些常量定义。其中的getter/setter
方法中包括了创建 Bean 实例所有可能用到的字段。所以它继承了两个接口:
-
AttributeAccessor
:定义了通用的getter/setter
,有点像Map
操作规范那种 -
BeanMetadataElement
: 定义了一个方法,用来获得生成此BeanDefinition
的数据源
定义的常量
/**
* 单例 Bean 的生命周期常量
*
* 注意,具体的实现类可能会扩展其他的生命周期常量。
*
* @see #setScope
*/
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
/**
* 原型 Bean 的生命周期常量
*
* 注意,具体的实现类可能会扩展其他的生命周期常量。
*
* @see #setScope
*/
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
/**
* Role hint indicating that a {@code BeanDefinition} is a major part
* of the application. Typically corresponds to a user-defined bean.
*/
// 角色提示。表明这个 BD 是应用中的关键角色。这个角色通常对应用户定义的 Bean
int ROLE_APPLICATION = 0;
/**
* Role hint indicating that a {@code BeanDefinition} is a supporting
* part of some larger configuration, typically an outer
* {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
* {@code SUPPORT} beans are considered important enough to be aware
* of when looking more closely at a particular
* {@link org.springframework.beans.factory.parsing.ComponentDefinition},
* but not when looking at the overall configuration of an application.
*/
// 角色提示,表明 BD 是一些大型配置的支撑角色。通常是一些外部框架的支撑 bean 。在梳理整体应用
// 配置时一般不关心它,但是在仔细查看特定框架实现时应该注意研读
int ROLE_SUPPORT = 1;
/**
* Role hint indicating that a {@code BeanDefinition} is providing an
* entirely background role and has no relevance to the end-user. This hint is
* used when registering beans that are completely part of the internal workings
* of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
*/
// 角色提示,表示 BD 完全是一个后台服务,不会和使用者直接接触。在注册完全在 ComponentDefinition 内部工作
// 的 BD 时会用这个
int ROLE_INFRASTRUCTURE = 2;
主要围绕 Bean 的生命周期和角色定义了一些常见的常量。
问题
为什么没有用 final
修饰,会不会被篡改?见最后的扩展。
定义的变量getter/setter
因为直接粘贴源码太长了,我们直接去掉get/set
取后面的名字来大概介绍都定义了哪些属性。
-
ParentName
: 返回此BeanDefinition
的父BD
的名称【id 或者 别名】 -
BeanClassName
: Bean 实例对应的类名【为什么不直接返回Class
类型呢?参见"想法——职责单一问题”】 -
Scope
:类的生命周期 -
LazyInit
:Bean 的初始化是否进行懒加载 -
DependsOn
:设置此 Bean 明确配置的依赖的 Bean。【后面会了解到,如果你在 Bean 中使用了对其他 Bean 的依赖注入,这个也算依赖,后面会维护在Factory
中。但是允许你主动配置或者新增对一些 Bean 的依赖】 -
AutowireCandidate
: 判断其他 Bean 是否允许依赖注入此 Bean -
Primary
: 其他 Bean 做依赖注入有多个候选人时,是否优先选此 Bean -
FactoryBeanName
:在使用工厂方法构造此 BD 的实例时,使用哪个工厂 -
FactoryMethodName
:在使用工厂方法构造此 BD 的实例时,使用工厂的哪个方法 -
ConstructorArgumentValues
: 使用构造函数创建此 BD 的实例时,配置了哪些入参 -
PropertyValues
:创建实例后使用getter/setter
方法填充实例属性时,要配置哪些入参 -
Role
: BD 对应的实例的角色 -
ResourceDescription
: 获得创建这个 BD 的源的描述信息 -
Source
: 获得创建这个 BD 的源 -
OriginatingBeanDefinition
:未知。。。。。。。。。
还有基于以上属性的一些判断函数,例如是不是单例、是不是原型之类的,不再赘述。
一些想法
程序员的思维
关于在写代码,搭建框架甚至是日常工作中的一些操作的思路:
- 尽可能的使用封装之后的东西,这样有问题你能找到负责的人,使用顺畅。而且封装之后往往意味着使用更加简单。【API接口】
- 在工作时对 API 问题进行沟通时尽可能绕过行话直接说原理,这样调用者能更好的把控整个流程,有时还能帮你找出一些问题。
- 在提供 SPI 时,和 API 不同的是,如果可行的话,提供一个接口,让调用者能够拿到最原始的数据,这样会使框架在某些情况下更方便用户进行定制。当然,要对自己的解析流程定好规范和校验,防止由于用户的不规范操作造成大范围的问题。
职责单一问题
在定义数据结构时,要明确你要的是什么?
BD
的职责只是一个用于存储的数据结构而已,在存储 Bean 对应的类时采用String
足以存储,该类名是从配置文件中读取的。不一定是对的,可能该类不存在,也可能未加载,如果在这里就传入Class
,那么在最开始的注册阶段就会引起大量的冗余引入、校验操作。
扩展
interface
中的常量定义没有用修饰词
-
interface
中的常量定义不用修饰,都是public static final
-
interface
中定义的方法不用修饰,都是public
【丢人!!!!】
网友评论