Spring框架源码干货分享之三级缓存和父子工厂
2024-09-07 11:06:13
记录并分享一下本人学习spring源码的过程,有什么问题或者补充会持续更新。欢迎大家指正!
环境: spring5.X + idea
建议:学习过程中要开着源码一步一步过
Spring中对象的创建宏观流程:
- 创建对象需要的基础数据:beanDefinition
在BeanFactory中getBean时做一下三步处理完成对象的创建
- 创建对象:AbstractAutowireCapableBeanFactory中
doCreateBean
createBeanInstance(beanName, mbd, args);
- 属性赋值:AbstractAutowireCapableBeanFactory中
doCreateBean
populateBean(beanName, mbd, instanceWrapper);
这里属性赋值也就是注入分为多种方式
a. 配置文件<bean autowired= "bytype|byname"/>
<beans default-autowired="bytype|byname"/>
b. 注解 @Autowired
- 对象初始化:AbstractAutowireCapableBeanFactory中
doCreateBean
initializeBean(beanName, exposedObject, mbd);
在初始化的过程中细分了几个部分分别是
a. aware
b. BeanPostProcessors
c. InitMethods
宏观流程了解清楚了之后,先分析一下createBean之前spring做了那些事,也就是Beanfactory调用
doGetBean
然后执行createbean
调用AbstractAutowireCapableBeanFactory中的doCreateBean
之前Spring还做了什么样的处理
上源码(createbean执行之前)
String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if(sharedInstance != null && args == null) {
//日志打印的
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
}
源码说明:else 之前就是创建对象之前做的一些事情
- 获取bean的id值:transformedBeanName(name)
说明
:从这个方法的命名就可以知道他是用来转化对象对象名的,Spring配置Bean的时候可以写id,name,别名,这里就是把这些转换成这个对象的唯一id供后续使用。 - 通过当前的id获取是否有已经创建好的对象:getSingleton(beanName)
说明
:从单例池中获取对象,然后判断是否获取到对应的对象,如果没有获取到就执行else去创建,如果获取到了Spring又做了一个普通对象还是实现了FactoryBean接口的对象,getObjectForBeanInstance,如果是普通对象直接返回,如果是实现了FactoryBean接口对象就会调用getObject方法返回。
三级缓存
:单例池最根本的实现是Spring设计了一个三级缓存,也就是DefaultSingletonBeanRegistry中的三个MapsingletonObjects
一级缓存earlySingletonObjects
二级缓存singletonFactories
三级缓存protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 执行else分支时Spring在调用createbean方法之前还做了一些父子工厂相关的处理
说明
:如果存在父子工厂,那么他们的配置会融合,发现同名配置会优先使用子工厂中的配置BeanFactory parentBeanFactory = this.getParentBeanFactory();
if(parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if(parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
if(args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
if(requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
return parentBeanFactory.getBean(nameToLookup);
}
说明
:获取父类工厂,如果存在父工厂并且子工厂中没有对应的BeanDefinition就从父工厂中递归查找,然后实例化对应的对象。如果父工厂中也没有找到当前的这个对象那就是自己创建,调用createBean
到doCreateBean
中执行创建对象的那几步。
最后
感谢您的阅读,有什么意见和问题欢迎评论区留言!书写不易!
觉得文章对你有帮助记得给我点个赞,欢迎大家关注和转发文章!
最新文章
- H5 表格标签基本使用
- ubuntu不能正常登录
- Easyui 异步树的实现
- freeCodeCamp:Mutations
- QThread
- WebView点击加载的页面中的按钮时不弹出新窗口以及在加载后执行javascript
- Android_Spinner_example
- CodeForces 220(div 2)
- HDU 1556 Color the ball - from lanshui_Yang
- AlarmManager类的应用
- Java设计模式之《单例模式》及应用场景
- java 图片转base64字符串、base64字符串转图片
- mysql 多列索引学习-经典实例
- 用js实现超链接导航菜单点击切换选中时的状态
- 简单的CSS圆形缩放动画
- VB.NET 编程元素支持更改总结
- [algorithm] 汉诺塔问题
- 7.2 C++模板类实例化
- 解决ie浏览器下载apk或ipa变为zip
- Ubuntu12.04下Qt连接MySQL数据库
热门文章
- [年薪60W分水岭]基于Netty手写Apache Dubbo(带注册中心和注解)
- [hdu6974]Destinations
- [loj3179]视觉程序
- es插件安装
- Rainbond通过插件整合SkyWalking,实现APM即插即用
- 基于Ubuntu 18.04.5 LTS 部署Ceph集群测试及Ceph RDB的使用。
- P6604 [HNOI2016]序列 加强版
- char *p、char p[]、字符串的几个题目
- Nginx编译安装相关参数
- PHP面试经常被问cgi、fastcgi、php-fpm、mod_php的区别