新星计划---学习Spring技术--03

1.为什么学习Spring?

Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90% 专业角度 简化开发,降低企业级开发的复杂性 框架整合,高效整合其他技术,提高企业级应用开发与运行效率.

学习Spring框架设计思想 学习基础操作,思考操作与思想间的联系 学习案例,熟练应用操作的同时,体会思想.


2.什么是bean?

bean就是spring中被spring容器管理的,或者实例化组装起来的对象。在实际的项目中,对象之间经常是依赖关系,比如A依赖B,那么A要等到B一切工作完成之后,才可以开始自己的工作。

Bean的生命周期:

1.实例化(Instantiation)

2.属性赋值(Populate)

3.初始化(Initialization)

4.销毁(Destruction)


3.什么是循环依赖?

 public class A {
 
     @Autowired
     private B b;
 
 }
 
 public class B {
 
     @Autowired
     private A a;
 
 }

A 里面注入 B,B 里面又注入 A。此时,就发生了“循环依赖”。

4.解决单例模式下的属性循环依赖--使用三级缓存技术

对于多例 Bean 和 Prototype 作用域的 Bean的循环依赖问题,并不能使用三级缓存设计解决

Spring 中,单例 Bean 在创建后会被放入 IoC 容器的缓存池中,并触发 Spring 对该 Bean 的生命周期管理。

保存单例模式的Bean的缓存池中,采用三级缓存技术:(代码如下所示)

 /** Cache of singleton objects: bean name --> bean instance */
 
 /** 一级缓存:用于存放完全初始化好的 bean **/
 
 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
 /** Cache of early singleton objects: bean name --> bean instance */
 /** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
 private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
 /** Cache of singleton factories: bean name --> ObjectFactory */
 /** 三级缓存:存放 bean 工厂对象,用于解决循环依赖 */
 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

其中,二级缓存和三级缓存都用于解决循环依赖,单例循环的依赖冲突问题可以从bean的生命周期来看,

1.实例化(Instantiation)

2.属性赋值(Populate)

当A要进行到第二步,属性赋值的时候,发现需要依赖B,但是B此时还处在未实例化的阶段。B要实例化,属性赋值的时候,又开始依赖A,但是A也没有完成属性赋值,,缓存中根本找不到完整的初始化对象。因此产生冲突,谁都初始化不了。

缓存层级

名称

描述

第一层缓存

singletonObjects

单例对象缓存池,存放的 Bean 已经实例化、属性赋值、完全初始化好(成品)

第二层缓存

earlySingletonObjects

早期单例对象缓存池,存放的 Bean 已经实例化但尚未属性赋值、未执行 init 方法(半成品)

第三层缓存

singletonFactories

单例工厂的缓存

5.getSingleton方法中三级缓存的使用

(1)Spring首先从singletonObjects(一级缓存)中尝试获取。

(2)若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取。

(3)若是仍是获取不到而且允许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()(三级缓存)获取。

(4)若是获取到了则将singletonObject放入到earlySingletonObjects,也就是将三级缓存提高到二级缓存中。

 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Spring首先从singletonObjects(一级缓存)中尝试获取
 
  Object singletonObject = this.singletonObjects.get(beanName);
   // 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
   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) {
             //若是仍是获取不到而且允许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()(三级缓存)获取
               singletonObject = singletonFactory.getObject();
               //若是获取到了则将singletonObject放入到earlySingletonObjects,也就是将三级缓存提高到二级缓存中
 
              this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
          }
        }
    }
 
  }
 
   return (singletonObject != NULL_OBJECT ? singletonObject : null);
 
 }
 

isSingletonCurrentlyInCreation() 方法用于判断当前单例 Bean 是否正在创建中,即“还没有执行初始化方法”。

比如,A 的构造器依赖了 B 对象因此要先去创建 B 对象,或者在 A 的属性装配过程中依赖了 B 对象因此要先创建 B 对象,这时 A 就是处于创建中的状态。

allowEarlyReference 变量表示是否允许从三级缓存 singletonFactories 中经过 singletonFactory 的 getObject() 方法获取 Bean 对象。

6解决单例Bean属性循环依赖的核心方法

将实例化的A使用下述方法,实例化过后直接放进第三级单例工厂缓存中去(此时,A属于直接越过属性赋值和初始化)

 public interface ObjectFactory<T> {
 
     T getObject() throws BeansException;
 
 }
 //三级缓存工厂提供了一个接口

创建bean时,有两处比较重要的匿名内部类实现了该接口。一处是 Spring 利用其建立 Bean 的时候,另外一处就是在 addSingletonFactory 方法中,如下代码所示。

 addSingletonFactory(beanName, new ObjectFactory<Object>() {
 
    @Override  
    public Object getObject() throws BeansException {
        return getEarlyBeanReference(beanName, mbd, bean);
    }
 
 });
 

这段代码发生在 createBeanInstance 以后,单例 Bean 对象A已经实例化(可以通过对象引用定位到堆中的对象),但尚未属性赋值和初始化。

文字描述:

  1. 创建对象 A,完成生命周期的第一步,即实例化(Instantiation),在调用 createBeanInstance 方法后,会调用 addSingletonFactory 方法,将已实例化但未属性赋值未初始化的对象 A 放入三级缓存 singletonFactories 中。即将对象 A 提早曝光给 IoC 容器。
  2. 继续,执行对象 A 生命周期的第二步,即属性赋值(Populate)。此时,发现对象 A 依赖对象,所以就会尝试去获取对象 B。
  3. 继续,发现 B 尚未创建,所以会执行创建对象 B 的过程。
  4. 在创建对象 B 的过程中,执行实例化(Instantiation)和属性赋值(Populate)操作。此时发现,对象 B 依赖对象 A。
  5. 继续,尝试在缓存中查找对象 A。先查找一级缓存,发现一级缓存中没有对象 A(因为对象 A 还未初始化完成);转而查找二级缓存,二级缓存中也没有对象 A(因为对象 A 还未属性赋值);转而查找三级缓存 singletonFactories,对象 B 可以通过 ObjectFactory.getObject 拿到对象 A。
  6. 继续,对象 B 在获取到对象 A 后,继续执行属性赋值(Populate)和初始化(Initialization)操作。对象 B 完成初始化操作后,会被存放到一级缓存中。
  7. 继续,转到「对象 A 执行属性赋值过程并发现依赖了对象 B」的场景。此时,对象 A 可以从一级缓存中获取到对象 B,所以可以顺利执行属性赋值操作。
  8. 继续,对象 A 执行初始化(Initialization)操作,完成后,会被存放到一级缓存中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值