石家庄老站长

点击联系客服
客服QQ: 客服微信:
 找回密码
 立即注册
查看: 67|回复: 0

[小明]你对弹簧3级缓存和循环依赖的理解[推荐收藏]

[复制链接]

1

主题

1

帖子

-7

积分

限制会员

积分
-7
发表于 2021-9-20 07:27:10 | 显示全部楼层 |阅读模式
一、什么是循环依赖?什么是三级缓存?

【什么是循环依赖】我很清楚什么是循环依赖。BeanA类依赖BeanB类注入,BeanB类注入A类时,IOC过程中creaBean实例化A后无法直接找到initbeanA。配置函数以创建B对象的实例化。另外,由于B对象需要注入A对象,如果发现对象池中还没有A对象,就可以戴玩偶。

【三级缓存】三级缓存实际上就是三个Map对象,从存放对象的顺序开始

L3缓存singletonFactories存储ObjectFactory,传递匿名内部类,ObjectFactory.getObject()方法最终通过调用getEarlyBeanReference()进行处理

二级缓存earlySingletonObjects存储bean,存储中间bean实例,当对象需要用AOP片替换时,存储代理bean的实例beanProxy

1级缓存(单个池)singletonObjects存储了整个bean实例

/* * cache  of  singleton  objects  : bean  name  to  bean  instance。*/

Private  final  mapstring,object  singleton  objects=new  concurrent  hashmap(256);

/* * cache  of  early  singleton  objects  : bean  name  to  bean  instance。* */

Private  final  mapstring,object  earlysingletonobjects=new  hashmap(16);

/* * cache  of  singleton  factories  : bean  name  to  object  factory。*/

Private  final  mapstring,object  factory?singleton  factories=new  hashmap(16);





二、三级缓存如何解决循环依赖?

[如何解决循环依赖]解决循环依赖关系的核心想法是提前暴露,先创建实例化的A,然后在三级缓存singletonFactories中存储实例化的A的LAM  BDA表达式,从而获得A实例。没有循环依赖和AOP时

但是,当A对象需要注入B对象时,发现缓存中还没有B对象,需要创建B对象,并按照上述方法将其添加到三级缓存singletonFactories中,B对象需要注入A对象。这时,从半成品缓存中获取半成品对象A,通过缓存的LAM  BDA表达式创建A实例对象,并将其放置在二级缓存Earlysingletonobe中。

B对象现在可以
以注入A对象实例和初始化自己,之后将完成品B对象放入完成品缓存singletonObjects。但是当有aop时,B对象还没有把完成品B对象放入完成品缓存singletonObjects中,B对象初始化后需要进行代理对象的创建,此时需要从singletonFactories获取bean实例对象,进行createProxy创建代理类操作,这是会把proxy&B放入二级缓存earlySingletonObjects中。这时候才会把完整的B对象放入完成品一级缓存也叫单例池singletonObjects中,返回给A对象。
         A对象继续注入其他属性和初始化,之后将完成品A对象放入完成品缓存。



三、使用二级缓存能不能解决循环依赖?

一定是不行,我们只保留二级缓存有两个可能性保留一二singletonObjectsearlySingletonObjects,或者一三singletonObjectssingletonFactories

【只保留一二singletonObjectsearlySingletonObjects】

流程可以这样走:实例化A ->将半成品的A放入earlySingletonObjects中 ->填充A的属性时发现取不到B->实例化B->将半成品的B放入earlySingletonObjects中->从earlySingletonObjects中取出A填充B的属性->将成品B放入singletonObjects,并从earlySingletonObjects中删除B->将B填充到A的属性中->将成品A放入singletonObjects并删除earlySingletonObjects。

这样的流程是线程安全的,不过如果A上加个切面(AOP),这种做法就没法满足需求了,因为earlySingletonObjects中存放的都是原始对象,而我们需要注入的其实是A的代理对象。

【只保留一三singletonObjectssingletonFactories】

流程是这样的:实例化A ->创建A的对象工厂并放入singletonFactories中 ->填充A的属性时发现取不到B->实例化B->创建B的对象工厂并放入singletonFactories中->从singletonFactories中获取A的对象工厂并获取A填充到B中->将成品B放入singletonObjects,并从singletonFactories中删除B的对象工厂->将B填充到A的属性中->将成品A放入singletonObjects并删除A的对象工厂。

同样,这样的流程也适用于普通的IOC已经有并发的场景,但如果A上加个切面(AOP)的话,这种情况也无法满足需求。

因为拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法,getEarlyBeanReference这个方法每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象

所有这里我们要借助二级缓存来解决这个问题,将执行了singleFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象。

getSingleton()、getEarlyBeanReference() 源码如下

        @Nullable
        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) {
                        // 最终会调用传入的匿名内部类getEarlyBeanReference()方法,这里面没调用一次会生成一个新的代理对象
                                                singletonObject = singletonFactory.getObject();
                                                this.earlySingletonObjects.put(beanName, singletonObject);
                                                this.singletonFactories.remove(beanName);
                                        }
                                }
                        }
                }
                return singletonObject;
        }
       
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
                Object exposedObject = bean;
                if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                        for (BeanPostProcessor bp : getBeanPostProcessors()) {
                                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                                        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                                        exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                                }
                        }
                }
                return exposedObject;
        }
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|无图版|手机版|小黑屋|石家庄@IT精英团

GMT+8, 2022-8-13 19:41 , Processed in 0.187194 second(s), 32 queries .

Powered by Discuz! X3.4

© 2001-2021 Comsenz Inc.

快速回复 返回顶部 返回列表