扯淡 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实现 蓝桥杯 算法训练 求和求平均值
试题 算法训练 求和求平均值 问题描述 从键盘输入10个浮点数,求出它们的和以及平均值,要求用函数实现 输入格式 测试数据的输入一定会满足的格式. 1 10 (1行10列的向量) 输出格式 要求用户的 ...
- Java实现 蓝桥杯VIP 算法训练 新生舞会
问题描述 新生舞会开始了.n名新生每人有三个属性:姓名.学号.性别.其中,姓名用长度不超过20的仅由大小写字母构成的字符串表示,学号用长度不超过10的仅由数字构成的字符串表示,性别用一个大写字符'F' ...
- Java实现 蓝桥杯VIP 算法训练 一元三次方程
问题描述 有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差 ...
- Java实现 LeetCode 188 买卖股票的最佳时机 IV
188. 买卖股票的最佳时机 IV 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你最多可以完成 k 笔交易. 注意: 你不能同时参与多 ...
- SQK Server实现 LeetCode 175 组合两个表
175. 组合两个表 SQL架构 表1: Person +-------------+---------+ | 列名 | 类型 | +-------------+---------+ | Person ...
- Spring事务的传播属性
前言 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为.事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为.这是Spring ...
- (三)Host头攻击
01 漏洞描述 为了方便获取网站域名,开发人员一般依赖于请求包中的Host首部字段.例如,在php里用_SERVER["HTTP_HOST"].但是这个Host字段值是不可信赖的( ...
- [bx] and loop
1.[bx] 表示一个内存单元,它的偏移地址在bx中 mov al,[bx] 2.描述符号() 来表示一个寄存器或一个内存单元中的内容. 约定符号idata表示常量. 3.loop 标号 CPU在执行 ...
- JSP基础知识点(转传智)
一.JSP概述 1.JSP:Java Server Pages(运行在服务器端的页面).就是Servlet. 学习JSP学好的关键:时刻联想到Servlet即可. 2.JSP的原理 ...
- zabbix 监控cpu 温度
Zabbix监控Linux主机CPU温度 一.客户端 1.客户Linux主机安装Im_sensors [root@localhost ~]# yum install -y lm-sensors-y ...