创建Bean系列三之记录创建Bean的ObjectFactory

doCreateBean创建bean的方法里有这样一段逻辑
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
   if (logger.isTraceEnabled()) {
      logger.trace("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
   }
   //为了避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//aop在这里将advice动态织入bean中,如没有则直接返回bean,不做任何处理
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;
}

一、earlySingletonExposure是提早曝光单例,曝光单例的条件如下

1、mbd.isSingleton()

2、this.allowCircularReferences

        是否允许循环依赖

3、isSingletonCurrentlyInCreation

        在Spring中会有专门属性默认为DefaultSingletonBeanRegistry类的this.singletonsCurrentlyInCreation属性来记录bean的加载状态,在bean开始创建前会将beanName加入到该属性中,在bean创建结束后会将beanName从属性中移除。

以之前分析的public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)函数里会执行beforeSingletonCreation(beanName)和afterSingletonCreation(beanName);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

当上述的三个条件都满足时,会执行addSingletonFactory。

二、加入SingletonFactory原理

假设A类有属性B,B类有属性A,那么初始化A的过程如下图

 通过上图可以看出,在实例化B的populate方法中又会再次初始化A,此时调用getBean(A),这个函数不是直接实例化A,而是先去检测缓存中是否已经创建好对应的bean,或者已经创建好对应的ObjectFactory。

Spring处理循环依赖的解决方法,在B中创建依赖A时通过ObjectFactory提供的实例化方法来中断A中属性的填充,使B中持有的A仅仅是刚初始化并没有填充任务属性的A,而这正初始化A的步骤还是在最开始创建A的时候进行,但是因为A与B中A所表示的属性地址是一样的,所以A中创建好的属性填充自然可以通过B中的A获取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值