单例Bean的创建流程
创始人
2024-06-03 12:29:38
0

简要介绍

bean的创建,需要经过查找,创建,注入,实例化三阶段

finishBeanFactoryInitialization

前言提到,refresh方法执行了finishBeanFactoryInitialization,这个方法便是完成了bean的创建与初始化。
每一个最后都会走向doGetBean

doGetBean

doGetBean是用于返回bean的方法,如果bean不存在,还会调用其内部的doCreateBean完成bean的创建

protected  T doGetBean(final String name, @Nullable final Class requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName = transformedBeanName(name);Object bean;// 从缓存池中获取Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {//如果存在,判断一下是否还在创建,都已经创建但是状态却是还在创建当然是错的。然后判断一下if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}//这是为了防止beanFactory套用beanFactory,这里提供了递归使用getObject方法,从而获取最终beanbean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// 空的,要不是没创建过的单例bean,要不是原型bean,并且这个bean一定不能是if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 打上已经创建的标记,防止对象反复创建if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// 优先完成@DependOn注解指定的类的bean的创建与获取String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 这里面实际上就是增加这个bean依赖了哪个bean,和哪个被依赖的bean被这个bean依赖的双重引用registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// 如果是单例if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});// 也是递归向里调用,直到返回的不是factoryBeanbean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();if (!StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");}final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new ScopeNotActiveException(beanName, scopeName, ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// 检查一下是否需要格式转换,比如XML的字符串转化为对象的类型if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;
}

试图直接返回

这是singletonObject的逻辑,如果一级有,直接返回,如果一级没有,那么就可能涉及修改操作,所以提前完成上锁。为什么锁的是一级缓存而不是二级缓存呢,正是因为三级缓存在完成调用之后会将对象加入二级缓存,然后其它有着相同需求正在等待的线程就可以直接从二级缓存取出对象,而不需要双重检验机制了。
然后进行二级和三级缓存的查找。如果是在三级缓存中找到的,那么就会调用其中getObject方法,这个方法在单例中就是getReference方法

//三级缓存,保存工厂
private final Map> singletonFactories = new HashMap<>(16);
//二级缓存,保存工厂创建的对象
private final Map earlySingletonObjects = new HashMap<>(16);
//一级缓存,保存所有完成创建的对象
private final Map singletonObjects = new ConcurrentHashMap<>(256);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;
}

doCreateBean方法的“AOP”

以下对源码的验证部分进行大量删除,只剩下主干
这个方法在调用doCreateBean之前,会将其加入一个set表示正在创建,在调用doCreateBean正常结束之后会将其删除,并完成一级缓存的添加和二三级缓存的清除

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {// 添加进入singletonsCurrentlyInCreation,表示是正在创建的单例对象beforeSingletonCreation(beanName);boolean newSingleton = false;try {//这里才是真正调用了 doCreateBeansingletonObject = singletonFactory.getObject();// 如果走到这里说明初始化成功了newSingleton = true;} finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}// 从singletonsCurrentlyInCreation中移除afterSingletonCreation(beanName);}// 如果初始化成功了,那么加入一级缓存if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}
}protected void addSingleton(String beanName, Object singletonObject) {// 将这个对象加入一级缓存,从二三级删除,并标记为已经注册synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}

doCreateBean的实体

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}// 实例化beanif (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 可以理解为走了一个beanPostProcessorssynchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);mbd.postProcessed = true;}}// 如果设置了属性,并且是正在创建的单例bean,就会添加单例工厂.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;// 注入属性populateBean(beanName, mbd, instanceWrapper);// 初始化beanexposedObject = initializeBean(beanName, exposedObject, mbd);// 如果支持循环引用,并且存在该对象,这是为了保证返回的一定是代理对象if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}}}// 如果需要回调destory方法,会放入destroybeans,这样在销毁的时候就会从destroybeans剔除并回调registerDisposableBeanIfNecessary(beanName, bean, mbd);return exposedObject;
}

关联的属性这时候注入

属性注入的时候对Autowire注解进行了注入

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}// 使用AutowiredAnnotationBeanPostProcessor,将类中所有Autowired注解都提取出来,并在postProcessPropertyValues逐一完成注入for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}// 把property数组放入beanWrapper里面,便于后续使用if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}
}

对于三级缓存的解释

比如A包含B,B包含A的关系,用户尝试获取A。
一开始进入A的getBean,由于缓存中不存在A,所以进入A的create方法,会生成单例工厂,并将单例工厂放入三级缓存,然后进入属性注入环节,会尝试注入B,这时陷入B的getBean。
B会标记自己是正在生成,然后进入create方法,生成单例工厂,并将单例工厂放入三级缓存,然后进入属性注入环节,会尝试注入A,这时陷入A的getBean,这时会从三级缓存中取出A的单例工厂,并且调用其getEarlyReference方法,AbstractAutoProxyCreator会将A加入AOP缓存,然后生成代理对象,并将A移出三级缓存,将其注入二级缓存,然后返回给B使用。B获取到之后会继续完成属性注入和初始化代理,然后从三级缓存中删除自己,加入一级缓存,返回代理对象B给A。
A拿到了B的代理对象,会继续完成属性注入和初始化代理,在初始化代理时候,A会检查AOP缓存,由于A会在AOP缓存里发现自己,所以直接返回。在create方法的最后,A会从二级缓存中取出A的代理,然后从二级缓存中删除A,并加入一级缓存,将A的代理返回给用户。
假设更麻烦一些,B在获取A的时候,C也在获取A,会怎样呢。由于进入二级和三级缓存都有同一把锁,比如B先进入了这把锁,那么它会先检查二级缓存是否有A,发现没有,会进入三级缓存取出A的工厂,通过A的工厂完成A的代理,再将其放入二级缓存,然后释放锁,这是C才会获取到这把锁,它会在二级缓存直接发现了A,于是直接注入,这就是二级缓存的作用。

相关内容

热门资讯

122.(leaflet篇)l... 听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
Vue使用pdf-lib为文件... 之前也写过两篇预览pdf的,但是没有加水印,这是链接:Vu...
PyQt5数据库开发1 4.1... 文章目录 前言 步骤/方法 1 使用windows身份登录 2 启用混合登录模式 3 允许远程连接服...
Android studio ... 解决 Android studio 出现“The emulator process for AVD ...
Linux基础命令大全(上) ♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维...
再谈解决“因为文件包含病毒或潜... 前面出了一篇博文专门来解决“因为文件包含病毒或潜在的垃圾软件”的问题,其中第二种方法有...
南京邮电大学通达学院2023c... 题目展示 一.问题描述 实验题目1 定义一个学生类,其中包括如下内容: (1)私有数据成员 ①年龄 ...
PageObject 六大原则 PageObject六大原则: 1.封装服务的方法 2.不要暴露页面的细节 3.通过r...
【Linux网络编程】01:S... Socket多进程 OVERVIEWSocket多进程1.Server2.Client3.bug&...
数据结构刷题(二十五):122... 1.122. 买卖股票的最佳时机 II思路:贪心。把利润分解为每天为单位的维度,然后收...
浏览器事件循环 事件循环 浏览器的进程模型 何为进程? 程序运行需要有它自己专属的内存空间࿰...
8个免费图片/照片压缩工具帮您... 继续查看一些最好的图像压缩工具,以提升用户体验和存储空间以及网站使用支持。 无数图像压...
计算机二级Python备考(2... 目录  一、选择题 1.在Python语言中: 2.知识点 二、基本操作题 1. j...
端电压 相电压 线电压 记得刚接触矢量控制的时候,拿到板子,就赶紧去测各种波形,结...
如何使用Python检测和识别... 车牌检测与识别技术用途广泛,可以用于道路系统、无票停车场、车辆门禁等。这项技术结合了计...
带环链表详解 目录 一、什么是环形链表 二、判断是否为环形链表 2.1 具体题目 2.2 具体思路 2.3 思路的...
【C语言进阶:刨根究底字符串函... 本节重点内容: 深入理解strcpy函数的使用学会strcpy函数的模拟实现⚡strc...
Django web开发(一)... 文章目录前端开发1.快速开发网站2.标签2.1 编码2.2 title2.3 标题2.4 div和s...