Spring框架系列之bean的生命周期底层原理08

接着上一篇,咱们继续doCreateBean方法的分析,doCreateBean内容比较多,我们这次主要是把它的整体流程说下,后续会逐个来分析每一个关键点。代码如下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }

   //关键点一
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

   final Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
           //关键点二
           applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }

   //关键点三
   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");
      }
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));  // AService
   }
 
   Object exposedObject = bean;
   try {
      //关键点四
      populateBean(beanName, mbd, instanceWrapper);  //

      //关键点五
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
         throw (BeanCreationException) ex;
      }else {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
      }
   }

   //关键点六
   if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false); 
      if (earlySingletonReference != null) {
         if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
         } 
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
               if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                  actualDependentBeans.add(dependentBean);
               }
            }
            if (!actualDependentBeans.isEmpty()) { 
               throw new BeanCurrentlyInCreationException(beanName,
                     "Bean with name '" + beanName + "' has been injected into other beans [" +
                     StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                     "] in its raw version as part of a circular reference, but has eventually been " +
                     "wrapped. This means that said other beans do not use the final version of the " +
                     "bean. This is often the result of over-eager type matching - consider using " +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }
 
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

关键点一

首次获取单例classA对象(续接“Spring框架系列之bean的生命周期底层原理07”的例子)肯定为空,这里会调用createBeanInstance实例化对象,何为实例化不用我多说了吧?就是new一个对象,既然是new一个对象,那如果ClassA这个类有多个构造函数咋办?Spring怎么知道调用哪个构造函数呢?所以这里Spring肯定需要有一个过程,用以推断具体的构造函数,这块我们放下一篇来详细展开。这里朋友们只要知道createBeanInstance方法就是通过new来得到一个对象,当然这里Spring是返回一个BeanWrapper类型的包装对象,对原始对象进行了封装。

关键点二

对象创建了以后,按照我们正常的java开发流程该做什么事情呢?是不是应该给对象的相关属性进行赋值了?Spring也是这么做的,但是Spring要明确知道,哪些属性是需要赋值的,这些属性赋值的方式是啥?是方法赋值还是属性赋值?

在Spring中有两个常见的注解是用来指定哪些属性是需要被赋值的,如Autowired、Value,当然还包括Inject,另外还有Resource等。在创建完成对象后,会调用
applyMergedBeanDefinitionPostProcessors方法来查找注入点,这些注入点就是被Autowired、Value、Resource这些注解标识的属性或者方法,具体怎么找的,我们放到后续篇幅详细分析,这里我们只需要知道通过applyMergedBeanDefinitionPostProcessors方法就能够找到具体的注入点,Spring将基于这些注入点进行赋值操作。

关键点三

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      isSingletonCurrentlyInCreation(beanName));

如上代码段,标识如果当前创建的是单例bean,并且允许循环依赖,并且还在创建过程中,那么则需要提早暴露,默认情况下allowCircularReferences是为true的,也就是说Spring默认情况下是允许循环依赖的,什么是循环依赖?就是就是我们的案例,ClassA依赖ClassB,ClassB又依赖ClassA。而且当前beanName实例肯定是在创建中的,所以这里earlySingletonExposure的值是true,于是Spring调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)),注意这里的第二个参数是一个lambda表达式,addSingletonFactory方法代码如下:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
      this.singletonFactories.put(beanName, singletonFactory);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}
}

该方法将lambda表达式添加到singletonFactories集合中,lambda表达式的执行代码如下:

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;
}

会执行SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法,大部分情况下getEarlyBeanReference返回的是原bean对象,除非AOP处理的情况下,这块我们后续讲AOP的时候详细分析。

关键点四

在找到注入点后,Spring接下来就是调用populateBean方法给属性赋值了,比如classA,需要给属性ClassB实例对象赋值,既然要赋值,那咱首先得有这个ClassB的实例对吧?但是此时Spring里面还没有ClassB这个类型的对象,所以在populateBean方法中又会进入ClassB对象的生命周期,来想下,当创建完ClassB的实例对象,也需要给ClassB对象的属性,也就是classA赋值,但是此时classA还不是一个健全的对象,于是出现了循环依赖问题,那Spring如何解决这个问题的呢?比较复杂,咱们后续会有专门篇幅分析。

关键点五

属性赋值完成后,调用initializeBean完成对象的初始化,以前笔者不是很明白初始化和实例化到底有啥区别,现在看来其实很简单,实例化就是JVM创建一个对象,而初始化则是需要结合实际的业务来看,更多的是业务层面的初始化操作。这里initializeBean方法其实执行了很多操作,比如执行Aware、初始化之前、初始化、初始化之后,具体我们后续篇幅分析。

关键点六

exposedObject = initializeBean(beanName, exposedObject, mbd),因为initializeBean方法中调用了后置处理器进行了处理,所以通过这个方法得到的exposedObject有可能已经被咱们自己增加的后置处理器修改了,如果咱们自己修改了,Spring认为我们的优先级会更高点,所有会使用咱们自己的,如果exposedObject == bean那么表示咱们自己没有修改bean对象,于是就使用Object earlySingletonReference = getSingleton(beanName, false)这个方法返回的值.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值