扯淡 Spring BeanDefinition
相关文章
- Spring 整体架构
- 编译Spring5.2.0源码
- Spring-资源加载
- Spring 容器的初始化
- Spring-AliasRegistry
- Spring 获取单例流程(一)
- Spring 获取单例流程(二)
- Spring 获取单例流程(三)
- Spring 循环依赖
- Spring FactoryBean 缓存
- Spring Aware 接口
- Spring beanPostProcessor


大多数的方法都能从它的名字知道它是干啥的、都能在 XML 配置文件中找到对应的配置项
大部分的实现是落在 AbstractBeanDefinition 中、里面的逻辑也并不是特别的复杂、毕竟只是一些 get/set 方法
对于它的三个子类 GenericBeanDefinition RootBeanDefinition ChildBeanDefinition 其实本质上来说、它们并无太大的区别、它们都继承了 AbstractBeanDefinition 、在它们各自的类中、并没有什么太大的特殊的逻辑、某种程度上来说、它们可以说是差别非常小的
我们在 Spring 容器初始化的时候、读取 XML 配置文件并注册 BeanDefinition 、这个BeanDefinition 是子类中的哪个类呢
// 解释 bean 标签的时候
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
最终它会落到这个工具类里面、创建的都是 GenericBeanDefinition
而在 BeanDefinitionRegistry 的实现类中、都是如此存储的
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
我们也是可以使用其他的 BeanDefinition 的子类注册
而我们在 getBean 的流程中的时候、当我们无法在三级缓存中获取到 bean 的时候、就开始了创建 bean 的流程、这个时候、就要从 beanDefinition 中获取相关信息创建 bean
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
我们可以在 AbstractBeanFactory 中找到
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
可以看到 Map 中的 value 的类型是 RootBeanDefinition
如果你在定义中存在了父子 bean、或者更加具体的说、就是在 BeanDefinition 中、你的parentName 不为空、作为子 bean、你就要合成父 bean 的一些属性
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
} else {
mbd = new RootBeanDefinition(bd);
}
} else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
......................
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
........
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
貌似到目前为止、我们还是没有看到 ChildBeanDefinition 使用的场景

貌似确实没啥用是吧在整一个 Spring 框架中、我的版本 5.2
但是呢、其实我们可以手动的创建一个 BeanDefiniton 注册给 Spring
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Company.class);
rootBeanDefinition.getPropertyValues().add("name", "XX");
rootBeanDefinition.getPropertyValues().add("numberOfPeople", "1000");
defaultListableBeanFactory.registerBeanDefinition("rootCompany", rootBeanDefinition);
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("rootCompany");
defaultListableBeanFactory.registerBeanDefinition("childCompany", childBeanDefinition);
System.out.println(defaultListableBeanFactory.getBean("rootCompany"));
System.out.println(defaultListableBeanFactory.getBean("childCompany"));
System.out.println(defaultListableBeanFactory.getBean("rootCompany") == defaultListableBeanFactory.getBean("childCompany"));
其实在 RootBeanDefinition 和 ChildBeanDefinition 中我们看到注释说、其实首选是 GenericBeanDefinition 、因为 RootBeanDefinition 不能够指定 parentName、而 ChildBeanDefinition 必须有 parentName、这在使用上是非常不灵活的


或许这就是 GenericBeanDefinition 出现的原因吧
在 AbstractAutowireCapableBeanFactory#doCreateBean 中

在创建好了一个 bean 的时候(不完整的 bean ),会对 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 进行回调、这个时候是比加入第三级缓存之前早一点
defaultListableBeanFactory.addBeanPostProcessor(new MergedBeanDefinitionPostProcessor() {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
System.out.println("beanName:" + beanName);
}
});

扯淡 Spring BeanDefinition的更多相关文章
- html5吹牛扯淡篇,闲话内容。
09年提出对媒体查询的草案,到今天的广泛运用,w3c带我们走进了个性化定制的殿堂.这些之所以会被认可会被写进世界级标准,因为他越来越适应广大用户的需求,需求就像一条锁链带动或者牵引整个互联网开发工作. ...
- 【转载】阎焱:90后创业是扯淡 大量O2O和P2P公司濒临倒闭
真正创业成功的大部分是年龄在30岁到38岁之间,很多90后基本什么都不懂.从历史来看,在这样的人口大国,集体性行为,无论是政治的还是经济的,基本都是导致灾难性后果. 10月14日消息,赛富基金创始首席 ...
- 扯扯淡,写个更快的memcpy
写代码有时候和笃信宗教一样,一旦信仰崩溃,是最难受的事情.早年我读过云风的一篇<VC 对 memcpy 的优化>,以及<Efficiency geek 2: copying data ...
- Java面试题之最扯淡的String
public class ThreadException { public static void main(String[] args) { 没加final的代码 String hello = &q ...
- dba和运维专家们说有丰富的大型分布式系统架构设计经验纯属扯淡
如果,一开始就从事dba和运维的专家们说他们有丰富的大型分布式系统架构设计经验,那纯属扯淡.除非,他们从是从开发专家或者架构师转型而来,那么他们才有资格说自己有丰富的大型分布式系统架构设计经验. 运维 ...
- 退役III次后做题记录(扯淡)
退役III次后做题记录(扯淡) CF607E Cross Sum 计算几何屎题 直接二分一下,算出每条线的位置然后算 注意相对位置这个不能先搞出坐标,直接算角度就行了,不然会卡精度/px flag:计 ...
- 驳"一切不谈考核的管理都是扯淡"
一.引子 以我个人的从业经验认为,研发人员的量化考核,始终是一个世界难题.正巧不久前在园子里看到了"一切不谈考核的管理都是扯淡!"一文(下面简称为"扯淡"),该 ...
- Spring BeanDefinition的加载
前面提到AbstractRefreshableApplicationContext在刷新BeanFactory时,会调用loadBeanDefinitions方法以加载系统中Bean的定义,下面将讲 ...
- 【扯淡篇】CTSC/APIO/SDOI R2时在干什么?有没有空?可以来做分母吗?
注意: 我比较弱, 并没有办法把外链bgm搞成https, 所以大家可以选择"加载不安全的脚本"或者把https改成http以获得更好的阅读体验! 据说, 退役了要写写回忆录. 但 ...
随机推荐
- Java实现蓝桥杯VIP算法训练 相邻字母
试题 算法训练 相邻字母 资源限制 时间限制:1.0s 内存限制:256.0MB [问题描述] 从键盘输入一个英文字母,要求按字母的顺序打印出3个相邻的字母,指定的字母在中间.若指定的字母为Z,则打印 ...
- Java实现硬币收集问题
1 问题描述 在n*m格木板中放有一些硬币,每格的硬币数目最多为一个,在木板左上方的一个机器人需要收集尽可能多的硬币并把它们带到右下方的单元格.每一步,机器人可以从当前的位置向右移动一格或向下移动一格 ...
- java实现测量到的工程数据
[12,127,85,66,27,34,15,344,156,344,29,47,-] 这是某设备测量到的工程数据. 因工程要求,需要找出最大的 5 个值. 一般的想法是对它排序,输出前 5 个.但当 ...
- Java实现第八届蓝桥杯日期问题
日期问题 题目描述 小明正在整理一批历史文献.这些历史文献中出现了很多日期.小明知道这些日期都在1960年1月1日至2059年12月31日.令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/ ...
- Mysql的默认最大连接数及如何修改
一.Mysql默认最大连接数 通过查看mysql安装目录的my.ini文件,发现mysql的默认最大的连接数为100,实际场景中,以及进行压测时,100时远远不够的,一般都会设置最大的连接数. 二.如 ...
- Python 图像处理 OpenCV (7):图像平滑(滤波)处理
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- mysql基础-数据类型和sql模式-学习之(三)
0x01 mysql的两种方向: 开发DBA:数据库设计(E-R关系图).sql开发.内置函数.存储历程(存储过程和存储函数).触发器.时间调度器(event scheduler) 运维----> ...
- [C#.NET 拾遗补漏]04:你必须知道的反射
阅读本文大概需要 3 分钟. 通常,反射用于动态获取对象的类型.属性和方法等信息.今天带你玩转反射,来汇总一下反射的各种常见操作,捡漏看看有没有你不知道的. 获取类型的成员 Type 类的 GetMe ...
- 阻塞队列一——java中的阻塞队列
目录 阻塞队列简介:介绍阻塞队列的特性与应用场景 java中的阻塞队列:介绍java中实现的供开发者使用的阻塞队列 BlockQueue中方法:介绍阻塞队列的API接口 阻塞队列的实现原理:具体的例子 ...
- 解决:gradle 前言中不允许有内容
将Android Studio 升级到4.0然后创建一个新项目,编译出现“ gradle 前言中不允许有内容” 的错误,在网上找了很多资料,众说纷纭,但都没有解决我的问题,最后反复摸索把问题解决了. ...