一、回顾下 bean的创建过程

image.png
5、Spring 容器和对象的创建流程

二、构造器注入的循环依赖

1、先创建两个循环依赖的类

  1. public class ServiceA{
  2. private ServiceB b;
  3. // 构造方法
  4. public ServiceA(ServiceB b){
  5. this.b = b;
  6. }
  7. }
  8. public class ServiceB{
  9. private ServiceA a;
  10. // 构造方法
  11. public ServiceB(ServiceA a){
  12. this.a = a;
  13. }
  14. }

2、然后 main 函数中调用,发现该依赖无法解决

  1. new ServiceA(new ServiceB(new ServiceA(.......)))

3、分析
上述流程进入了一个闭环
image.png

三、Set 方式注入

设置两个循环依赖的类

  1. public class ServiceBB{
  2. private ServiceAA aa;
  3. // set方法
  4. public void setServiceAA(ServiceAA serviceAA){
  5. this.aa = serviceAA;
  6. }
  7. }
  8. public class ServiceAA{
  9. private ServiceBB bb;
  10. // set方法
  11. public void setServiceBB(ServiceBB servicebb){
  12. this.bb = servicebb;
  13. }
  14. }

然后main函数调用,set可以解决循环调用,因为new的时候是调用一个空的无参构造方法,此时并没有依赖。
原因是 spring 内部用到了 三级缓存 解决这个问题。

  1. public class test{
  2. public static void main(String[] args){
  3. ServiceAA a = new ServiceAA();
  4. ServiceBB b = new ServiceBB();
  5. b.setServiceAA(a);
  6. a.setServiceBB(b);
  7. }
  8. }

image.png

四、三级缓存

1、简单介绍

在实例化的过程中,将处于半成品的对象全部都放到缓存中,方便后续来进行调用,只要有了当前对象的引用地址,那么后续来进行赋值也可以。 半成品对象放到了map缓存结构中,成品对象要不要也放到某一个map中,能否把成品和半成品对象放到一起?如果放到一起,就会导致获取对象的时候获取到半成品对象,值为空。 为了将成品和半成品对象完全的区分开,那么可以创建两个缓存对象,即两个map,当然还有第三个map,这就是三级缓存。 一级:成品对象 二级:半成品对象 三级:?为什么需要这个三级缓存

2、三级缓存代码位置

image.png

  1. public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
  2. /** Cache of singleton objects: bean name to bean instance. */
  3. // 一级
  4. // 单例池:存放了已经经历了完整生命周期的bean对象,即已经初始化好的bean,也就是所谓的单例池
  5. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  6. /** Cache of singleton factories: bean name to ObjectFactory. */
  7. // 三级 存放可以生成Bean的工厂,存放FactoryBean。假如A类实现了FactoryBean,那么依赖注入的时候不是A类,而是A类产生的Bean
  8. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  9. /** Cache of early singleton objects: bean name to bean instance. */
  10. // 二级
  11. // 存放早期暴露出来的bean对象,Bean的生命周期未结束(属性还没有填充完整),即存放的是实例化一半的bean
  12. private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

DefaultListableBeanFactory#preInstantiateSingletons —》 getbean—>doGetBean—>如下代码
image.png
image.png

  1. Object singletonObject = this.singletonObjects.get(beanName);
  2. // 如果一级缓存为空,则执行如下代码
  3. if (singletonObject == null) {

继续走下去,从传进的 singletonFactory 中获取 getObject
image.png
我们看看传进来的 singletonFactory 是什么,如下,是个 Lambda表达式,进入 createBean
image.png
—》doCreateBean
image.png
然后看到这个方法里面调用了 addSingletonFactory 方法。
image.png
addSingletonFactory 方法如下

  1. /**
  2. * Add the given singleton factory for building the specified singleton
  3. * if necessary.
  4. * <p>To be called for eager registration of singletons, e.g. to be able to
  5. * resolve circular references.
  6. * @param beanName the name of the bean
  7. * @param singletonFactory the factory for the singleton object
  8. */
  9. protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  10. Assert.notNull(singletonFactory, "Singleton factory must not be null");
  11. // 使用 singletonOjects 加锁,保证线程安全
  12. synchronized (this.singletonObjects) {
  13. //如果一级单例对象的高速缓存map【bean名称->bean实例】没有beanName的对象
  14. if (!this.singletonObjects.containsKey(beanName)) {
  15. // 将 beanname,singletonFactory 放到单例工厂的缓存(三级)【bean名称 - ObjectFactory】
  16. this.singletonFactories.put(beanName, singletonFactory);
  17. // 将二级单例对象的高速缓存【bean名称->bean实例】释放beanName的相关缓存
  18. this.earlySingletonObjects.remove(beanName);
  19. // 将 beanName 添加到已注册的单例集合中
  20. this.registeredSingletons.add(beanName);
  21. }
  22. }
  23. }

(populateBean)接着进行bean属性的填充,或者可能依赖于其他bean 的属性的,则会递归初始化依赖的bean
image.png
populateBean—》applyPropertyValues—》 valueResolver.resolveValueIfNecessary—》resolveReference—》 this.beanFactory.getBean —》doGetBean —》Object sharedInstance = getSingleton(beanName);
�注意:这次的 getSingleton,和上面的 getSingleton不一样,这个的没有 lambda方法,
image.png
image.png

  1. @Nullable
  2. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  3. // Quick check for existing instance without full singleton lock
  4. Object singletonObject = this.singletonObjects.get(beanName);
  5. // 正在创建中
  6. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  7. // 从二级缓存里面取
  8. singletonObject = this.earlySingletonObjects.get(beanName);
  9. // 二级缓存中没有,并且允许创建二级缓存
  10. if (singletonObject == null && allowEarlyReference) {
  11. // 锁定全局变量进行处理
  12. synchronized (this.singletonObjects) {
  13. // Consistent creation of early reference within full singleton lock
  14. singletonObject = this.singletonObjects.get(beanName);
  15. if (singletonObject == null) {
  16. singletonObject = this.earlySingletonObjects.get(beanName);
  17. if (singletonObject == null) {
  18. // 当某些方法需要提前初始化的时候则会调用 addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonfactories里面
  19. // 三级缓存中取
  20. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  21. if (singletonFactory != null) {
  22. // 如果存在单例工厂,则通过工厂创建一个单例对象
  23. singletonObject = singletonFactory.getObject();
  24. // 记录在缓存中,二级缓存和三级缓存的对象不能同时存在
  25. this.earlySingletonObjects.put(beanName, singletonObject);
  26. // 移除三级缓存
  27. this.singletonFactories.remove(beanName);
  28. }
  29. }
  30. }
  31. }
  32. }
  33. }
  34. return singletonObject;
  35. }

�。。。。。。。有空自己debug吧

  1. protected void addSingleton(String beanName, Object singletonObject) {
  2. synchronized (this.singletonObjects) {
  3. this.singletonObjects.put(beanName, singletonObject);
  4. this.singletonFactories.remove(beanName);
  5. this.earlySingletonObjects.remove(beanName);
  6. this.registeredSingletons.add(beanName);
  7. }
  8. }

五、疑问

1、三级缓存汇总分别保存的是什么对象

1、成品对象 2、半成品对象 3、lambda表达式

2、如果只使用1级缓存行不行?

不行,因为成品和半成品对象会放到一起,在进行对象获取的时候有可能会获取到半成品对象,这样的对象是没办法使用的。

3、如果只有二级缓存,将三级缓存去掉 行不行?

getSingleton、doCreateBean 中用到了二级缓存 只有二级缓存的时候,也可以解决循环依赖问题。

但是AOP就不能用了。会报错 this mean that said other beans do not use the final version of the bean ,没有使用最终版本的bean对象

4、三级缓存存在到底是干什么用的?

如果一个对象需要被代理,生成代理对象,那么这个对象需要预先生产非代理对象吗? 需要

三级缓存到底干了什么? lamdba.getEarlyBeanReference(),只要搞清楚这个方法的具体执行逻辑即可。 当前方法中,有可能会用代理对象替换非代理对象,如果没有三级缓存的话,那么就可能无法得到代理对象,即在整个容器中,包含了同名对象的代理对象和非代理对象,这是不行的。 容器中,对象都是单例的,意味着根据名称只能取到一个对象的值,如果没有三级缓存,那这个代理对象就有可能存放在二级缓存中,那就可能冲突了。所以在三级缓存中完成了代理对象替换非代理对象的工作,确定返回的是唯一对象。 所以三级缓存是为了解决在 aop 代理过程中产生的循环依赖问题,如果没有 aop的话,二级缓存足以。

image.png
image.png
image.png
上图中最后返回的代理对象,会被放到三级缓存中去。
image.png
image.png