【细品springboot源码】彻底弄懂spring bean的创建过程(下)

==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍


接着上一篇【细品springboot源码】彻底弄懂spring bean的创建过程(上),说到了doCreateBean这个方法,开始创建bean,老规矩,贴关键代码,标号对着解释。

  • 剖析创建Bean的源码

    • 普通bean的创建过程三
      接着往下运行,到了真正创建bean的地方
      在这里插入图片描述
       protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      	throws BeanCreationException {
      
      	// Instantiate the bean.
      	BeanWrapper instanceWrapper = null;
      	if (mbd.isSingleton()) {
      	    //1.尝试从FactoryBean缓存中拿实例
      		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
      	}
      	if (instanceWrapper == null) {
      	    //2.如果1没拿到,那么创建实例
      		instanceWrapper = createBeanInstance(beanName, mbd, args);
      	}
      	……
      	// Allow post-processors to modify the merged bean definition.
      	synchronized (mbd.postProcessingLock) {
      		if (!mbd.postProcessed) {
      			try {
      			    //3.主要是将@Autowired和@Value标记的属性解析出来,提供给后续使用
      				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
      			}
      			catch (Throwable ex) {
      				……
      			}
      			mbd.postProcessed = true;
      		}
      	}
         
          //4.判断是否允许提前暴露引用
      	// Eagerly cache singletons to be able to resolve circular references
      	// even when triggered by lifecycle interfaces like BeanFactoryAware.
      	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      			isSingletonCurrentlyInCreation(beanName));
      	if (earlySingletonExposure) {
      	    //5.将bean提前加入缓存中
      		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
      	}
      
      	// Initialize the bean instance.
      	Object exposedObject = bean;
      	try {
      	    //6.本方法的重点,属性注入
      		populateBean(beanName, mbd, instanceWrapper);
      		//7.初始化Bean
      		exposedObject = initializeBean(beanName, exposedObject, mbd);
      	}
      	catch (Throwable ex) {
      		……
      	}
          
          //8.
      	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()) {
      					……
      				}
      			}
      		}
      	}
      
      	// Register bean as disposable.
      	try {
      	    //9.注册销毁bean的东西
      		registerDisposableBeanIfNecessary(beanName, bean, mbd);
      	}
      	catch (BeanDefinitionValidationException ex) {
      		……
      	}
      
      	return exposedObject;
      }
      
    1. 尝试从FactoryBean缓存中拿实例
      为什么会有这一步呢?我们可以在当前文件下搜一下factoryBeanInstanceCache这个属性在哪里用到了。因为代码太长,截图看不完,所以直接将该方法贴出来,并且省去无关部分。这个方法是做啥的呢?它只是为了做类型检查。

      @Nullable
      private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
      	synchronized (getSingletonMutex()) {
      	    //尝试从factoryBeanInstance缓存中拿(这里还不知道是不是FactoryBean)
      		BeanWrapper bw = this.factoryBeanInstanceCache.get(beanName);
      		if (bw != null) {
      		    //拿到就直接返回了(拿到了就确认是了)
      			return (FactoryBean<?>) bw.getWrappedInstance();
      		}
      		//如果factoryBeanInstanceCache中没有,那么尝试从单例缓存中拿
      		Object beanInstance = getSingleton(beanName, false);
      		if (beanInstance instanceof FactoryBean) {
      		    //需要先判断是不是FactoryBean
      			return (FactoryBean<?>) beanInstance;
      		}
      		//判断是不是正在创建,(是不是FactoryBean&是不是正在创建),
      		if (isSingletonCurrentlyInCreation(beanName) ||
      				(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
      			return null;
      		}
      		Object instance;
      		try {
      		    //这里只是标记一下正在创建
      			// Mark this bean as currently in creation, even if just partially.
      			beforeSingletonCreation(beanName);
      			//BeanPostProcessor大家都懂了
      			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      			instance = resolveBeforeInstantiation(beanName, mbd);
      			if (instance == null) {
      			    //如果BeanPostProcessor什么都没做,那么就正常的创建这个bean
      				bw = createBeanInstance(beanName, mbd, null);
      				instance = bw.getWrappedInstance();
      			}
      		}
      		catch (UnsatisfiedDependencyException ex) {
      			// Don't swallow, probably misconfiguration...
      			throw ex;
      		}
      		catch (BeanCreationException ex) {
      			……
      			return null;
      		}
      		finally {
      		    //标记一下这个bean已经创建完成
      			// Finished partial creation of this bean.
      			afterSingletonCreation(beanName);
      		}
      		//getFactoryBean里面很简单,就是判断一下instance是不是FactoryBean,不是的话就报错了
      		FactoryBean<?> fb = getFactoryBean(beanName, instance);
      		if (bw != null) {
      		    //这里我也有个疑问,为什么fb不为null,bw为null的时候,不把instance放进来?
      			this.factoryBeanInstanceCache.put(beanName, bw);
      		}
      		return fb;
      	}
      }	
      
    2. 如果1没拿到,那么创建实例
      这个创建实例没啥好说的,有一个值得注意的地方是,如果是@Configuration标记的类中的@Bean创建,它有这么一段逻辑

      if (mbd.getFactoryMethodName() != null) {
      	return instantiateUsingFactoryMethod(beanName, mbd, args);
      }
      

      相当于代码中有这种bean的时候,会走instantiateUsingFactoryMethod这个逻辑,感兴趣的可以看一下。

      @Configuration
      public class B {
          @Bean
          public F f(){
              return new F();
          }
      }	
      
    3. bean合并后的处理
      主要是将@Autowired和@Value标记的属性解析出来,提供给后续使用。我们可以粗略的看一下代码。
      在这里插入图片描述
      然后看一下那个接口都在哪里被实现了,主要看一下划线的那个
      在这里插入图片描述
      像是在找什么信息在这里插入图片描述
      碍于篇幅,这里不细致讲下去了,推荐一篇文章MergedBeanDefinitionPostProcessor和@Autowired,@Value

    4. 判断是否允许提前暴露引用
      必须是单例,还要当前bean正在创建中,例如A创建的时候,需要创建B,这时候,A需要提前暴露引用,防止B引用了A,造成循环引用。

    5. 将bean提前加入缓存中
      addSingletonFactory就比较有趣了,可以看到,第二个参数是一个lambda表达式,实际上代码是这样的

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

      再来看看spring随处可见的getSingleton方法

       @Nullable
       protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            //先尝试从第一级缓存拿
       	Object singletonObject = this.singletonObjects.get(beanName);
       	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) {
       				     //注意注意,这里调用getObject的时候,就会跳到刚才那里,去执行getEarlyBeanReference方法了
       					singletonObject = singletonFactory.getObject();
       					//然后将它放到第二级中
       					this.earlySingletonObjects.put(beanName, singletonObject);
       					//第三级就应该删除了
       					this.singletonFactories.remove(beanName);
       				}
       			}
       		}
       	}
       	return singletonObject;
       }	
      

      这下子知道spring的骚操作了吧

    6. 属性注入
      这个就是doCreateBean的重点了,所以放到下面单独拿出去讲

    7. 初始化Bean
      为什么会有这一步呢?我们都知道,spring给了我们很多可扩展的接口,包括bean实例化之前、实例化之后、初始化之前、初始化之后可以由我们自由控制。所以initializeBean方法里,其实就是各种开放接口。可以简单看一下代码

      protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
      	……
      	//1.调用实现了Aware接口的类的方法
          invokeAwareMethods(beanName, bean);
      	Object wrappedBean = bean;
      	if (mbd == null || !mbd.isSynthetic()) {
      	    //2.初始化之前可以对bean干一些xxx事
      		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      	}
          ……
      	 //3.调用bean的初始化方法
      	invokeInitMethods(beanName, wrappedBean, mbd);
      	……
      	if (mbd == null || !mbd.isSynthetic()) {
      	    //4.初始化之后可以再对bean强行干一些xxx事
      		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
      	}
      	return wrappedBean;
      }
      

      这一块不展开讲,后续单独开一篇讲,还挺有意思的。

    8. 不知道是干啥的
      就连书上的解释都懵懵懂懂,我给你们引用看一下,反正我是没懂,以后遇到再说吧。

      之前有提到过,在Sping中解决循环依赖只对单例有效,而对于prototype的bean,Spring没有好的解决办法,唯一要做的就是抛出异常。在这个步骤里面会检测已经加载的 bean 是否已经出现了依赖循环,并判断是否需要抛出异常。

    9. 注册销毁bean的东西
      这个和初始化类似,到时候和它一起说

    • 普通bean的创建过程四
      最后,到属性注入了,革命的胜利就快来临了!
      话不多说,源码走起
      protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
      	……
      	//1.很显然,还要再给人家一次机会,在这个bean设置属性之前xxx这个bean
      	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
      	// state of the bean before properties are set. This can be used, for example,
      	// to support styles of field injection.
      	boolean continueWithPropertyPopulation = true;
      
      	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      		for (BeanPostProcessor bp : getBeanPostProcessors()) {
      			if (bp instanceof InstantiationAwareBeanPostProcessor) {
      				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
      					continueWithPropertyPopulation = false;
      					break;
      				}
      			}
      		}
      	}
          //2.漂亮,到这里了,还可以不让人家set属性 
      	if (!continueWithPropertyPopulation) {
      		return;
      	}
      
      	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
          
          //3.如果设置了根据XX类型来查找bean注入,就会进入if循环,默认是AUTOWIRE_NO
          //这个我也很迷,我一直得到的灌输是,@Autowire是默认根据Type进行注入的(继续往代码里面看,确实是根据type进行注入的)
      	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
      	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      		// Add property values based on autowire by name if applicable.
      		if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
      			autowireByName(beanName, mbd, bw, newPvs);
      		}
      		// Add property values based on autowire by type if applicable.
      		if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      			autowireByType(beanName, mbd, bw, newPvs);
      		}
      		pvs = newPvs;
      	}
      
      	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
      	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
      
      	PropertyDescriptor[] filteredPds = null;
      	if (hasInstAwareBpps) {
      		if (pvs == null) {
      			pvs = mbd.getPropertyValues();
      		}
      		for (BeanPostProcessor bp : getBeanPostProcessors()) {
      			if (bp instanceof InstantiationAwareBeanPostProcessor) {
      				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      				//4.设置属性之前的处理,在这里,会将需要注入的bean准备好
      				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
      				if (pvsToUse == null) {
      					if (filteredPds == null) {
      						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      					}
      					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
      					if (pvsToUse == null) {
      						return;
      					}
      				}
      				pvs = pvsToUse;
      			}
      		}
      	}
      	if (needsDepCheck) {
      		if (filteredPds == null) {
      			filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      		}
      		checkDependencies(beanName, mbd, filteredPds, pvs);
      	}
      
      	if (pvs != null) {
      	    //5.将属性设置上去
      		applyPropertyValues(beanName, mbd, bw, pvs);
      	}
      }
      
      属性注入这一块,还有很多地方值得讲,在这么短的篇幅里也不能说的尽兴,所以创建bean的过程到这里就结束了吧。
  • 总结

    • 创建bean的四个地方,顺序依次是prepareContextinvokeBeanFactoryPostProcessorsregisterBeanPostProcessorspreInstantiateSingletons,其中前三个都是对那些特殊的bean先进行创建,最后对普通的bean进行创建。
    • preInstantiateSingletons方法中可以知道,被@Lazy标注的bean不会被创建。想了解@Lazy注解,可以看一下这篇【追根究底】@Lazy注解为什么会失效?
    • 整个创建bean的流程,可以看出spring命名方法的一些端倪,都是在doXXX方法中真正的去获取/创建
    • 解决循环引用的地方是doCreateBean方法中,实例化bean之后,将未初始化的bean加入SingletonFactory
    • populateBean属性注入,就是注入那些被@Autowired@Value标注的属性
    • 创建bean的过程中,会有很多地方给BeanPostProcessor机会,提前结束或者改变bean的创建
    • 其实bean的创建是递归的,属性注入的时候,也是bean的创建。
    • 其实bean的创建管理很简单,只是spring帮我们做了很多事,就像我们写很多ifelse那样,写多了,也就看起来复杂了。

  • 没涉及或者没细讲的点
    • createBean中的prepareMethodOverrides方法
    • createBean中的resolveBeforeInstantiation方法
    • doCreateBean中的createBeanInstance方法
    • doCreateBean中的applyMergedBeanDefinitionPostProcessors方法
    • doCreateBean中的populateBean方法
    • doCreateBean中的initializeBean方法
    • doCreateBean中的registerDisposableBeanIfNecessary方法

啊~,写之前以为能把所有都一次性讲清楚,但是一开始写,整理思路的时候,才知道,要把这些全写出来,得花好多时间,这代码也太复杂了点。看来只能慢慢以后再补充了。(自己懂是一回事,将自己懂的表述给别人,并且让别人懂,那真的又是一回事了,这时间膨胀得厉害啊!)
最后,有不懂的下方评论留言,我应该能答上来,哈哈!

原创文章 257 获赞 277 访问量 69万+

猜你喜欢

转载自blog.csdn.net/qq_18297675/article/details/103560928
今日推荐