Spring源码解析——Bean加载(doCreateBean方法补充)

Posted 兴趣使然の草帽路飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码解析——Bean加载(doCreateBean方法补充)相关的知识,希望对你有一定的参考价值。


1. doCreateBean方法解析

还是一样的步骤,先来整体分析一下doGreateBean方法,后面再详细分步骤解析:

/**
 * 核心方法(真正创建Bean的方法):创建Bean实例对象,并且生命周期的动作大部分都在这里
 */
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

   // BeanWrapper:包装对象,内部最核心的字段就是咱们的真实实例。它提供了一些额外的接口方法,比如属性访问器
   BeanWrapper instanceWrapper = null;
   // 如果是单例,则先清除缓存
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   // 如果缓存中没有找到对应的结果:
   if (instanceWrapper == null) {
        // 则创建Bean实例,并将其包装到BeanWrapper实例中
        // createBeanInstance方法创建出来真实的bean实例:
        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) {
         // 应用MergedBeanDefinitionPostProcessors
         try {
            // 后处理器调用点:合并bd信息,因为接下来就是populate处理依赖了.. 
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            ... // 抛异常
         }
         mbd.postProcessed = true;
      }
   }

   // 是否需要提早曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
         ... // 日志打印
      }
      // 为避免后期循环依赖,可以在bean初始化完成之前将创建实例的ObjectFactory加入工厂
      addSingletonFactory(beanName,
            // 对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPostProcessor
            // 其中我们熟知的AOP就是这样将advice动态织入bean中,若没有则直接返回bean,不做任何处理
            () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      // 对bean进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归初始依赖bean
      // 处理当前实例的依赖数据...依赖注入在这一步完成的。
      populateBean(beanName, mbd, instanceWrapper);
      // 调用初始化方法,比如init-method
      // 生命周期中的初始化方法的调用:
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
         ... // 抛异常
      }
      else {
         ... // 抛异常
      }
   }

   if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false);
      // earlySingletonReference只有在检测到有循环依赖的情况下才会不为空
      // 条件成立:说明当前bean实例 从 2级缓存获取到了...
      // 说明产生循环依赖了...3级缓存 当前对象的ObjectFactory.getObject() 被调用过
      if (earlySingletonReference != null) {
         // 如果exposedObject没有在初始化方法中被改变,也就是没有被增强
         // 条件成立有几种情况?
		// 1.当前“真实实例”不需要被代理
		// 2.当前“实例”已经被代理过了...是在ObjectFactory.getObject() 方法调用时 实现的增强代理。
         if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
         }
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            // 获取依赖当前bean的 其它beanName
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
               // 检测依赖
               if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                  actualDependentBeans.add(dependentBean);
               }
            }
            // 为什么有问题?
            // 因为bean创建后其所依赖的bean一定是已经创建的
            // actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有没全部创建完,也就是说存在循环依赖
            if (!actualDependentBeans.isEmpty()) {
               ... // 抛异常
            }
         }
      }
   }

   try {
      // 判断当前bean实例是否需要注册 析构回调。当容器销毁时,会给当前bean的析构方法进行回调。
      // 根据scope注册bean
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      ... // 抛异常
   }

   return exposedObject;
}

上面代码中,我们整体串了一遍doCreateBean方法的整体流程,为了减少代码量和文章篇幅,代码中省略了错误日志打印和异常抛出。

我们来总结一下上面代码的执行过程:

  • 获取BeanWrapper:如果是单例模式,首先从缓存中尝试 remove 移除对应的 Bean 对象,移除后该方法返回 BeanWrapper对象。

    // Instantiate the bean.实例化bean。
    // BeanWrapper:包装对象,内部最核心的字段就是咱们的真实实例。它提供了一些额外的接口方法,比如 属性访问器
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
    	instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    
  • 获取BeanWrapper:如果缓存中没有找到目标结果,则通过createBeanInstance方法创建 Bean 实例(根据 BeanDefinition 最终结果转换为 BeanWrapper对象)

    // 如果缓存中没有找到对应的结果:
    if (instanceWrapper == null) {
    	// 则创建Bean实例,并将其包装到BeanWrapper实例中
    	// createBeanInstance方法创建出来真实的bean实例:
    	instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    
  • Bean 的依赖进行处理、填充、属性注入,并进行循环依赖检查,检测已经加载的 bean 是否已经出现了依赖循环,并判断是否要抛出异常:

    // 是否需要提早曝光:单例&允许循环依赖&当前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加入工厂
    	// 对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPostProcessor
    	// 其中我们熟知的AOP就是这样将advice动态织入bean中,若没有则直接返回bean,不做任何处理
    	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
    	// 依赖注入在这一步完成:对bean进行填充,将各个属性值注入,
        // 其中,可能存在依赖于其他bean的属性,则会递归初始依赖bean
    	populateBean(beanName, mbd, instanceWrapper);
    	// 调用初始化方法,比如init-method
    	// 生命周期中的初始化方法的调用:
    	exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
    	if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
    		... // 抛异常
    	}
    	else {
    		... // 抛异常
    	}
    }
    
    if (earlySingletonExposure) {
    	Object earlySingletonReference = getSingleton(beanName, false);
    	// earlySingletonReference只有在检测到有循环依赖的情况下才会不为空
    	if (earlySingletonReference != null) {
    		// 条件成立有几种情况?
    		// 1.当前“真实实例”不需要被代理
    		// 2.当前“实例”已经被代理过了...是在ObjectFactory.getObject() 方法调用时 实现的增强代理。
    		if (exposedObject == bean) {
    			exposedObject = earlySingletonReference;
    		}
    		else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    			// 获取依赖当前bean的 其它beanName
    			String[] dependentBeans = getDependentBeans(beanName);
    			Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
    			for (String dependentBean : dependentBeans) {
    				// 检测依赖
    				if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    					actualDependentBeans.add(dependentBean);
    				}
    			}
    			// 为什么有问题?
    			// 因为咱们当前对象的AOP操作是在 当前方法的 initializeBean 这个方法完成的。
    			// 在这之前 外部其它bean持有到的当前的 “bean实例” 都是尚未增强的。
    			if (!actualDependentBeans.isEmpty()) {
    				... // 抛异常
    			}
    		}
    	}
    }
    
  • 注册 DisposableBean。如果XML配置了 destory-method,这里需要注册以便于销毁 bean 的时候调用;

    // 判断当前bean实例是否需要注册 析构回调。当容器销毁时,会给当前bean的析构方法进行回调。
    // 根据scope注册bean
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
    
  • 完成创建并返回

    return exposedObject;
    

接下来一步一步的详细分析一下:

2. 获取BeanWrapper

在分析createBeanInstance方法之前,先来了解一下 BeanWrapper 类以及它的作用:

  • 在Spring框架中,数据的提供是由 BeanDefinition 这个类来负责,而依赖的注入就需要通过 BeanWrapper
  • 可以把BeanWrapper 理解为是一个代理器,Spring框架会委托 BeanWrapper 去完成 Bean 属性的填充工作。
  • BeanWrapper 是一个接口,因此Bean 属性的填充工作实际上是交给其实现类 BeanWrapperImpl 去完成!

doCreateBean方法中,调用createBeanInstance创建BeanWrapper实例之前,会先尝试从缓存中获取 BeanWrapper 对象( 从factoryBeanInstanceCache 中进行 remove,并获取该方法的返回值,返回的结果就是BeanWrapper实例)。

如果缓存中没有,我们需要调用 createBeanInstance() 方法根据指定 Bean 使用对应的策略创建新的 BeanWrapper 实例。

// Instantiate the bean.实例化bean。
// BeanWrapper:包装对象,内部最核心的字段就是咱们的真实实例。它提供了一些额外的接口方法,比如 属性访问器
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
	instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}

// 如果缓存中没有找到对应的结果:
if (instanceWrapper == null) {
	// 则创建Bean实例,并将其包装到BeanWrapper实例中
	// createBeanInstance方法创建出来真实的bean实例:
	instanceWrapper = createBeanInstance(beanName, mbd, args);
}

下面就来分析,创建BeanWrapper实例的方法:createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

/**
 * 创建beanWrapper的实例
 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
 * factory method, constructor autowiring, or simple instantiation.
 * @param beanName
 * @param mbd RootBeanDefinition
 * @param args
 * @return 返回一个BeanWrapper对象
 */
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // 解析bean对象的class类型
   Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
   // 三个条件: 
   // beanClass != null --> bean对象的class类型不为null
   // !Modifier.isPublic(beanClass.getModifiers() ---> 表示class是非public类型的
   // !mbd.isNonPublicAccessAllowed() ---> bd中nonPublicAccessAllowed字段值为false
   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
       // 上述三个条件均成立,就抛异常
       ... // 抛异常
   }

   // 通过指定的Supplier获取bean(JDK8 Spring5)
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   // 如果mbd中factoryMethodName不为空,则使用工厂方法初始化策略
   if (mbd.getFactoryMethodName() != null)  {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // 表示bd对应的构造信息是否已经解析成可以反射调用的构造方法method信息了...
   boolean resolved = false;
   // 是否自动匹配构造方法..
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         // 一个类有多个构造函数,每个构造函数都有不同的参数,所以调用前需要先根据参数锁定构造函数和对应的工厂方法
         // resolvedConstructorOrFactoryMethod缓存这构造函数或工厂方法
         // 如果条件成立:说明bd的构造信息已经转化成可以反射调用的method了...
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            // 当resolvedConstructorOrFactoryMethod 有值时,且构造方法有参数,那么可以认为这个字段值就是true。
		   // 只有什么情况下这个字段是false呢?
		   // 1.resolvedConstructorOrFactoryMethod == null
		   // 2.当resolvedConstructorOrFactoryMethod 表示的是默认的构造方法,无参构造方法。
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   // 如果已经解析过则使用缓存中已经解析好的构造函数方法不需要再次锁定
   if (resolved) {
      if (autowireNecessary) {
         // 构造函数自动注入
         // 如果有参数,那么就需要根据参数 去匹配合适的构造方法了...
         // 拿出当前Class的所有构造器,然后根据参数信息去匹配出一个最优的选项,然后执行最优的构造器创建出实例。
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 使用默认构造函数构造(无参构造方法处理)
         return instantiateBean(beanName, mbd);
      }
   }

   // 典型的应用:@Autowired 注解打在了构造器方法上(需要根据参数解析构造函数...)
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   // 条件一:成立,后处理指定了构造方法数组
   // 条件二:mbd autowiredMode 一般情况是no
   // 条件三:条件成立,说明bean信息中配置了 构造参数信息。
   // 条件四:getBean时,args有参数..
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      // 构造函数自动注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }
   // 未指定构造参数,未设定偏好...则使用默认的无参数的构造方法进行创建实例
   return instantiateBean(beanName, mbd);
}

下面我们重点去分析一下autowireConstructor这个方法:

2.1 autowireConstructor

对于实例的创建Spring中分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量工作。

/**
 * 带有参数的构造方法实例化
 * @param beanName 
 * @param mbd RootBeanDefinition
 * @param chosenCtors 候选构造函数(如果没有,则为 null)
 * @param explicitArgs 
 * @return 返回一个BeanWrapper对象
 */
public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
      @Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {

   BeanWrapperImpl bw = new BeanWrapperImpl();
   this.beanFactory.initBeanWrapper(bw);

   Constructor<?> constructorToUse = null;
   ArgumentsHolder argsHolderToUse = null;
   Object[] argsToUse = null;

   // explicitArgs通过getBean方法传入
   // 如果getBean方法调用的时候指定了方法参数那么直接使用
   if (explicitArgs != null) {
      argsToUse = explicitArgs;
   }
   // 如果getBean方法调用的时候没有指定方法参数则尝试从缓存中解析
   else {
      Object[] argsToResolve = null;
      // 尝试从缓存中获取
      synchronized (mbd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
         if (constructorToUse != null && mbd.constructorArgumentsResolved) {
            // 从缓存中获取
            argsToUse = mbd.resolvedConstructorArguments;
            if (argsToUse == null) {
               // 配置的构造函数参数
               argsToResolve = mbd.preparedConstructorArguments;
            }
         }
      }
      // 如果缓存中存在
      if (argsToResolve != null) {
         // 解析参数类型,如给定方法的构造函数A(int, int)则通过此方法后就会把配置中的("1", "1")转换为(1, 1)
         // 缓存中的值可能是原始值也可能是最终值
         argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
      }
   }

   // 如果没有被缓存,则从配置文件的配置下手
   if (constructorToUse == null) {
      // Need to resolve the constructor.
      boolean autowiring = (chosenCtors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
      ConstructorArgumentValues resolvedValues = null;

      int minNrOfArgs;
      if (explicitArgs != null) {
         minNrOfArgs = explicitArgs.length;
      }
      else {
         // 提取配置文件中的配置的构造函数参数
         ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
         // 用于承载解析后的构造函数参数的值
         resolvedValues = new ConstructorArgumentValues();
         // 能解析到的参数个数
         minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
      }

      // Take specified constructors, if any.
      Constructor<?>[] candidates = chosenCtors;
      if (candidates == null) {
         Class<?> beanClass = mbd.getBeanClass();
         try {
            candidates = (mbd.isNonPublicAccessAllowed() ?
                  beanClass.getDeclaredConstructors() : beanClass.getConstructors());
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                  "] from ClassLoader [" + beanClass.getClassLoader

以上是关于Spring源码解析——Bean加载(doCreateBean方法补充)的主要内容,如果未能解决你的问题,请参考以下文章

spring源码之bean加载(bean解析下篇)

Spring源码分析bean的加载

Spring源码解析——Bean加载(doCreateBean方法补充)

Spring源码解析——Bean加载(doCreateBean方法补充)

Spring源码--03--加载bean的定义信息---Spring注解解析原理

Spring源码解析-applicationContext.xml加载和bean的注册