创建A对象
给A对象进行实例化操作:Map:A 的半成品,查询是否有B;B的半成品;B成品,A成品
给A对象的B属性赋值
判断容器中是否有B对象
有:直接赋值
没有
创建B对象
给B对象进行实例化操作
给B对象的A属性赋值
判断容器中是否有A对象
没有
创建A对象... 循环开启...
将对象按照状态来分类:
成品:完成实例化,完成初始化
半成品:完成实例化但未完成初始化
Q:当持有了某一个对象的引用之后,能否在后续步骤的时候给对象进行赋值操作?
A:可以,实例化和初始化可以分开执行。
构造器解决不了,创建对象必须赋值。
Map:A 的半成品,查询是否有B;B的半成品;B成品,A成品
Q:如何区分成品和半成品?
各级缓存的缓存结构?
A:三级缓存。
ConcurrentHashMap<String,Object> singletonObjects 一级缓存 256
ConcurrentHashMap<String,Object> earlySingletonObjects 二级缓存 16
HashMap<String,ObjectFactory<?>> singletonFactories 三级缓存 16
ObjectFactory:函数式接口,可以将lambda表达式作为参数放到方法实参中,在方法执行的时候,并不会实际调用当前lambda表达式,只有在调用getObject方法的时候才会去调用lambda表达式
三级缓存:
key:a
value:()->getEarlyBeanReference(beanName,mbd,bean)
key:b
value:()->getEarlyBeanReference(beanName,mbd,bean)
二级缓存:key:a value:A@1761半成品
存入二级缓存后,将三级缓存中的内容移除(因为永远是先查123顺序,3级缓存之后用不到)
一级缓存:
key:b
value :B@2182 成品对象
key:a
value:B@2182成品
RuntimeBeanReference
getBean
doGetBean
createBean
doCreateBean
createBeanInstance
populateBean
Q1:三个缓存结构map分別存储什么类型的对象
1:成品
2:半成品
3:lambda表达式
Q2:三个缓存结构map的查找顺序?
A:123
Q3:如果只有一个map结构,能解决循环依赖问题吗?
理论上可行,实际上每人这么干,使用2个map的意思在于将半成品和成品对象进行区分,半成本对象是不能直接暴露给外部对象使用的。
可行的话:设计复杂的map,将成品和半成品状态用标志位区分,但操作代码较麻烦,直接用2个map較方便
Q4:如果只有2个map结构,能解决循环依赖问题吗?
可以,但是有前提:没有代理对象的时候,当不使用aop的時候,2个缓存就可以解决循环依赖
Q5:为什么使用三级缓存之后,就可以解决带aop的循环引用?
5-1 一个容器中,能包含同名的2个对象吗? 不能
5-2 对象创建过程中,原始对象有没有可能需要生成代理对象?有可能
5-3 如果创建出了代理对象,那么程序在调用的时候到底使用原始对象还是代理对象?
应该用代理对象,但是程序是死的,是提前写好的,他怎么知道要选择代理对象呢?
所以当出现代理对象的时候,要使用代理对象替换掉原始对象
5-4 代理对象的创建是在初始化过程的扩展阶段,而属性的赋值是在生成代理对象之前执行的,那么怎么完成替换呢?
需要在属性赋值的时候判断是否需要生成代理对象
5-5 那为什么非要使用 lambda表达式的机制来完成呢?
对象在什么时候被暴露出去或者被其他对象引用是没办法提前确定好的,所以只有在被调用的那一刻才可以进行原始对象还是代理对象的判断,使用lambda表达式是一种回调机制,不暴露的时候不需要调用执行,当需要被调用的时候,才真正执行lambda表达式,来判断返回的到底是代理对象还是原始对象。
创建A
放3级缓存,放lambda表达式,因为a不知道什么时候被调用
给A赋值B
创建B对象
放3级缓存,放lambda表达式,因为b不知道什么时候被调用
给B赋值A
此时需要判断赋值的时候到底是原始对象还是代理对象,调用lambda表达式来确定返回的到底是什么对象。