一次Spring Bean 对象debug过程

一次Spring Bean 对象debug过程


概述

  1. 用了Spring 这么久,除了觉得它对于web开发十分便利之外,并没有太多地了解它内部的一些实现过程。之前听人提起过,debug的方式可以带你一步一步跟着框架的执行思路了解它的内部机制,因此尝试了一下;( 懒得分开写,文字很多,嫌麻烦可以直接翻到最后的流程图 )

  2. 标准的SpringBoot项目,断点的代码比较简单:

  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    @Service
    public class UserService { //断点处

    @Autowired
    private UserMapper userMapper;

    public int addUser(User user){
    return userMapper.insert(user);
    }

    public User getUser(Integer userId){
    return userMapper.selectByPrimaryKey(userId);
    }

    public User getUserByName(String userName){
    return userMapper.getUserByName(userName);
    }
    }
  4. 断点打在第三行,类加载的时候


过程

零散的执行流程:

  1. 最先执行到的Spring 相关联的代码是 BeanUtilsinstantiateClass(Constructor<T> ctor, Object... args),根据形参的构造方法和对象参数,返回一个当前对象的实例,值得注意的是它会捕获四个异常:

    1. 当试图实例化一个抽象类时,捕获 InstantiationException异常
    2. 当构造函数是私有修饰时,捕获 IllegalAccessException 异常,这在反射中也能见到
    3. 当构造函数参数不合法时,捕获IllegalArgumentException异常
    4. 当反射调用异常时,捕获InvocationTargetException,这个异常是一个受检查异常,通常由被引用的方法或者构造函数抛出
  2. 一路 StepOver 就到了 SimpleInstantiationStrategy 类的 instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) 方法,这个方法的参数中有两个是比较显眼的String beanName 和 BeanFactory owner,分别是实例化的 bean 的名字和所属的 beanFactory 实例,类名是 UserService,@Service 注解中也没有声明任何beanName相关的信息,所以看到的信息如下:

  3. RootBeanDefinition bd 对象里面可以看到关于当前这个bean 的一些信息 ,值得一看的是 :

  4. scope = singleton , 说明这是个单例的bean

  5. beanClass =class producer.service.UserService , 这个bean是 UserService 类的实例

  6. lazyInit = null , 是否延迟初始化,这里是 null ,表示不会延迟初始化

  7. awtowireMode = 0,简单翻译成注入模式,这个属性的定义并不在RootBeanDefinition里面,而是它从父类 AbstractBeanDefinition继承过来的,取值共有四种,分别对应 AutowireCapableBeanFactory的四个属性:

    1. int AUTOWIRE_NO = 0 , 不指定具体的bean注入方式,表示继续使用 BeanFactoryAware 和 注解驱动的注入
    2. int AUTOWIRE_BY_NAME = 1,通过 beanName 注入
    3. **int AUTOWIRE_BY_TYPE = 2 **,通过bean类型注入
    4. int AUTOWIRE_CONSTRUCTOR = 3 ,构造方式注入
    5. int AUTOWIRE_AUTODETECT = 4,自行检查选择合适的注入方式,不过从 Spring 3.0 开始标记为废弃,推荐使用注解驱动的注入方式代替混合注入方法
  8. beanName = "userService ",因为没有指定 beanName,所以使用类构造的方法名作为beanName

  9. ower ,是 DefaultListableBeanFactory的实例,这说明,注解驱动模式下,使用的BeanFactory 实现是 DefaultListableBeanFactory 类;对象持有一个 beanDefinitionMap属性,里面放了啥呢?所有已经获取到的BeanDetinition对象信息,如下图所示:

  1. 咱们来捋一捋 :

    1. DefaultListableBeanFactory 是什么 ? Bean 容器对吧,它继承了 AbstractAutowireCapableBeanFactory抽象类,实现了 ConfigurableListableBeanFactory接口;

    2. beanDefinitionMap里面放了啥? 已经获取到的 BeanDefinition对象的信息对吧;了解过spring bean 创建的朋友肯定知道,spring的bean对象并不是立刻创建的,也就是 createBean这个动作只会发生在真正需要bean对象的时候,在这之前所有的Bean对象信息都保存在 bean 容器的 beanDefinitionMap

    3. 既然它是个map,那肯定有key对吧,有哪些 key 呢?瞄一眼:

    4. 没有瞎的朋友们肯定看明白了,这里的key有两种 ; 实例对象的名称和类型。记得前面的 bean注入模式中有name注入,type注入;这意味只需要提供 beanName 或者 bean的类信息就可以获得对应的 BeanDefinition信息并且以此来创建Bean实例

  2. 到这里大致看明白了一些bean注入模式实现的信息,继续往下;

  3. 下一步跳转到 AbstractAutowireCapableBeanFactoryinstantiateBean方法参数是String beanName,RootBeanDefinition bd,根据beanName使用默认构造创建bean实例;这里开始就是创建bean对象相关的东西了,这里返回了一个beanInstance ,从哪里来的呢 ? 就是从上面的过程中返回过来的 :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements 
    AutowireCapableBeanFactory{
    ......
    protected BeanWapper instantiateBean(final String beanName,final RootBeanDrfinition mbd){
    ......
    Object beanInstance = getInstantiationStrategy().instantiate();
    ......
    }
    }

    //上面这个调用指向了
    public class SimpleInstantiationStrategy implements InstantiationStrategy{
    ......
    @Override
    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName,
    BeanFactory owner){
    ......
    return BeanUtils.instantiateClass(constructorToUse);
    ......
    }
    ......
    }
    //很好,这个翻译过来叫做 `简单初始化策略`的类,调用了 BeanUtils.instantiateClass(contructorToUse)方法,参数是要创建的对象的构造方法
    public abstract class BeanUtils{
    ......
    public static <T> T instantiateClass(Constructor<T> ctor, Object... args){
    ......
    return (KotlinDetector.isKotlinReflectPresent()
    && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
    KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
    ......
    }
    ......
    }
    //这里还进行了是否属于Ktolin反射对象的判断,如果不是则最后调用 Constructor 类的newInstance(args)方法进行实例化并返回
  4. 实例化了 beanInstance 之后,开始创建 BeanWapper对象,我看了一眼此时的 userService 对象,发现它是这样的:

    beanInstance之后

  5. userService 内部是注入了 UserMapper userMapper;对象的,但是这时候还是个null,也就是这个bean对象的属性注入并没有完成,先接着看BeanWapper。BeanWrapper是个啥?文档的注释是:

    1
    2
    3
    4
    >Provides operations to analyze and manipulate standard JavaBeans:
    >the ability to get and set property values (individually or in bulk),
    >get property descriptors, and query the readability/writability of properties.
    >

    提供基本Bean对象的分析和管理能力,包括设置属性值,获取属性修饰符,读写权限等。wapper直接翻译过来是包装的意思,这个 BeanWapper 可以理解成 Bean 实例的包装类,拥有bean实例的属性信息并且可以进行设置等。

  6. 现在debug进行到的方法是doCreateBean方法,贴一下代码帮助理解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd,
    final @Nullable Object[] args){

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
    //如果当前bean定义信息表明是个单例的bean对象,会从FactoryBean name 和 BeanWapper
    //的缓存集合中移除当前bean对象
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
    //这里就是前面返回的beanWapper对象
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 用来获取beanWapper对象包装的bean对象
    final Object bean = instanceWrapper.getWrappedInstance();
    //获取Bean实例的类型
    /*(这里先记一下:不明白为什么不直接把bean对象拿来用?)*/
    Class<?> beanType = instanceWrapper.getWrappedClass();

    ......

    }

    到这里已经是获取到了 bean 对象本身和 bean 对象的类,虽然有点疑问为什么不直接把bean对象信息拿出来用而是加了个BeanWapper。

  7. 下面的东西就比较令人在意,提到了循环引用

    先说下循环引用的概念:假设A依赖BB依赖CC依赖A,那么在对A,B,C三个Bean进行实例化的时候,会发现要是实例化A需要完成属性B的实例化,而要实例化B,需要完成属性C的实例化,而C则需要属性A的实例化,一个循环就形成了,谁的实例化条件都无法满足。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 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) {
    if (logger.isTraceEnabled()) {
    logger.trace("Eagerly caching bean '" + beanName +
    "' to allow for resolving potential circular references");
    }
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    这里的 earlySingletonExposure是通过三个条件判断的:是否单例bean是否允许循环引用当前bean对象是否正在创建。满足这三个条件的情况下,会做两件事:提前获取bean对象的引用将这个引用添加到指定的单例工厂中
    addSingletonFactory()方法是DefaultSingletonBeanRegistry类的方法,会根据beanName判断指定的bean对象是否存在于单例的bean集合中,如果不存在,通过 this.singletonFactories.put(beanName, singletonFactory);将bean对象和参数的单例工厂绑定起来,并将beanName添加到已注册单例集合中。调用的方法是这两个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47


    /**
    * Obtain a reference for early access to the specified bean,
    * typically for the purpose of resolving a circular reference.
    * @param beanName the name of the bean (for error handling purposes)
    * @param mbd the merged bean definition for the bean
    * @param bean the raw bean instance
    * @return the object to expose as bean reference
    */
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    // 判断了当前的RootBeanDefinition 对象是否是应用自身创建的bean对象
    // 判断当前bean 是否添加了前置初始化回调方法,InstantiationAwareBeanPostProcessor 接口
    // 提供了bean创建之前的回调方法和bean初始化之后但是属性显示设置之前或自动注入发生之前的回调
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
    //这一步没看大明白,因为当bp 是 SmartInstantiationAwareBeanPostProcessor的实例时
    //会直接返回参数的bean对象,
    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
    }
    }
    }
    return exposedObject;
    }


    /**
    * Add the given singleton factory for building the specified singleton
    * if necessary.
    * <p>To be called for eager registration of singletons, e.g. to be able to
    * resolve circular references.
    * @param beanName the name of the bean
    * @param singletonFactory the factory for the singleton object
    */
    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);
    }
    }
    }

    方法注释的意思大致是:为了在必要时候创建指定的bean对象而添加给定的单例工厂对象,有点拗口。这里提到了四个缓存集合:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /** Cache of singleton objects: bean name to bean instance. */
    // 单例bean的缓存,beanName = bean 的映射
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name to ObjectFactory. */
    // 单例工厂的缓存, beanName = ObjectFactiry 对象的映射
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance. */
    // 提前创建的 bean对象的缓存集合, beanName 和 bean实例的映射
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /** Set of registered singletons, containing the bean names in registration order. */
    // 根据bean的注册顺序缓存的bean集合
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    顺序是:先查找单例对象缓存集合是否缓存了当前bean对象 ,如果没有缓存,将当前的beanName 和单例工厂对象缓存起来,从 earlySingletonObjects 缓存中移除当前 beanName 对应的对象,将 beanName 对应的实例作为已注册bean缓存起来。这里是个考点,当前正在创建的允许循环引用的单例bean,会缓存到已注册bean缓存集合中

    但是到这一步为止,userService的bean对象本身还没有创建完成,它依赖的bean userMapper 并没有被注入,接下来会调用populateBean(beanName, mbd, instanceWrapper);方法,根据 beanDefinition 中的bean的定义填充bean属性,这里可以延申一下思维:bean的属性也是个bean的话该怎么办?当然是原谅…哦不是,当然是先实例化它了~

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    ......
    Object exposedObject = bean;
    try {
    //根据beanDefinition 的bean信息进行bean的属性填充,
    //不过我debug看到 RootBeanDefinition mbd 的propertiesValues 的集合为空,没有需要填充的属性
    populateBean(beanName, mbd, instanceWrapper);
    //这里就是初始化bean了,主要是调用初始化方法和一些前置和后置初始化回调方法,
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    ......
    //如果是允许提前初始化的bean,就获取bean的引用
    if (earlySingletonExposure) {
    //从缓存中查找bean的引用,
    Object earlySingletonReference = getSingleton(beanName, false);
    ......
    // 判断是否存在依赖当前bean的bean对象,因为如果存在,则说明当前bean已经被创建过了,
    // 会抛出一个 BeanCurrentlyInCreationRxception 异常
    else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    String[] dependentBeans = getDependentBeans(beanName);
    ......
    }
    }
    ......
    //注册bean
    try {
    //将参数的bean 对象加入到bean容器的一次性bean集合中
    //会注册bean的 DisposableBean 接口(当destory方法需要释放资源的时候实现此接口)
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    ......
    }
    ......

    //上面调用的 initializeBean 方法
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    ......
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
    //应用前置初始化回调,bean如果存在属性的情况下,已经由 populateBean()填充完毕
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
    //反射初始化方法
    //会判断是否实现了InitializingBeannit 接口,决定是否调用 afterPropertiesSet 方法
    //没有实现此接口的情况下,会反射去查找指定的初始化方法
    invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
    throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDescription() : null),
    beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
    }

    bean注册完成那一步,整个doCreateBean方法就执行完成了,不过上面的过程理解整体看起来比较零散,现在尝试把它们的流程整合一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        
    doCreateBean(String beanName,RootBeanDefinition mbd,Object[] args)
    --> 判断当前bean定义信息是否是单例
    -->如果当前创建的是单例bean对象,则从 FactoryBean 和 BeanWapper 的映射中获取bean引用
    --> 前面获取到的bean如果是空,则需要进行BeanWapper 对象的创建,注意这里还只是BeanWapper 对象
    --> 然后加锁,获取当前bean对象的其他BeanDefinition信息,进行合并
    --> 接下来就是处理循环依赖的场景了,首先提前获取了bean的引用,在已注册的bean缓存中查找指定的bean对象,判断是否是已经实例化的bean对象,如果不是;则将beanName和beanFactory实例缓存起来
    --> 然后就是开始初始化bean对象,进行bean对象的属性填充和应用初始化以及初始化回调方法
    --> 将完成了属性填充之后开始注册bean对象,同时注册bean的destory方法,在应用停止的时候调用
    --> 返回bean对象
  8. doCreateBean 的过程看起来是这样的,但是我还是没有明白哪里体现出来了处理循环引用的问题,尝试debug向下走,一直返回到AbstractBeanFactorydoGetBean(String name,SClass<T> requiredType,Object[] args,boolean typeCheckOnly)方法,这里最开始就会尝试从缓存中查找当前需要创建的bean对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    protected <T> T doGetBean(......){
    ......
    //从缓存中查找当前bean对象
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
    ......
    if (isSingletonCurrentlyInCreation(beanName)) {
    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
    "' that is not fully initialized yet - a consequence of a circular reference");
    }
    ......
    }


    //最终指向的 getSingleton(beanName,true)方法
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从第一层缓存中查找beanName对应的bean对象
    Object singletonObject = this.singletonObjects.get(beanName);
    //如果bean不存在且正在创建中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    //锁住第一层缓存,防止并发写入
    synchronized (this.singletonObjects) {
    //从第二层缓存中查找指定的bean
    singletonObject = this.earlySingletonObjects.get(beanName);
    //如果仍然为空且允许提前获取bean的引用
    if (singletonObject == null && allowEarlyReference) {
    //尝试从第三层缓存中查找beanName 对应的 beanFactory 对象
    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    if (singletonFactory != null) {
    singletonObject = singletonFactory.getObject();
    this.earlySingletonObjects.put(beanName, singletonObject);
    this.singletonFactories.remove(beanName);
    }
    }
    }
    }
    return singletonObject;
    }

    如果当前需要的bean正在创建中,且缓存中不存在,则返回空,说明bean没有被创建过;如果获取到了非空的bean对象,但是对象正在创建中,那说明由于处理循环引用,bean对象还没有实例化完成;获取到空的bean对象时也会先进行bean对象是否正在创建的判断,为了避免对bean对象的重复创建。

  9. 接下来就是查找BeanDefinition信息,如果存在BeanDefinition信息那么也可以根据这些信息构造出bean对象来:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    // Check if bean definition exists in this factory.
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    //可能出现自定义beanName找不到bean对象的情况,尝试将beanName解析成规范化的名称重新调用doGetBean
    String nameToLookup = originalBeanName(name);
    if (parentBeanFactory instanceof AbstractBeanFactory) {
    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
    nameToLookup, requiredType, args, typeCheckOnly);
    }
    else if (args != null) {
    // Delegation to parent with explicit args.
    return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else if (requiredType != null) {
    // No args -> delegate to standard getBean method.
    return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    else {
    return (T) parentBeanFactory.getBean(nameToLookup);
    }
    }

    当通过类型,参数,规范化的beanName等任意一种方式获取到bean对象之后都会直接返回bean对象;

  10. 如果也不存在BeanDefinition信息的话,只能通过beanName等参数去创建Bean,会先将当前bean依赖的bean对象都初始化完成,再来创建当前bean对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    // Guarantee initialization of beans that the current bean depends on.
    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
    for (String dep : dependsOn) {
    //如果它们之间还存在反向的依赖关系,则是循环依赖
    if (isDependent(beanName, dep)) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    }
    //注册当前beanName依赖的depBean对象
    registerDependentBean(dep, beanName);
    try {
    //检查是否成功初始化了依赖的depBean对象
    getBean(dep);
    }
    catch (NoSuchBeanDefinitionException ex) {
    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
    }
    }
    }

重新梳理完整的过程:

  1. 这里要先确定一些东西,上面零散的debug过程,是从BeanUtils类开始的,但这明显是个底层的工具类方法,从这里开始是看不明白的,debug的过程是从代码执行的最深处向上返回,所以上面的执行过程应该反过来看好理解一点

  2. 起点

    1. AbstractBeanFactory.doGetBean(String name,Class<T> requiredType,Object[] args,boolean typeCheckOnly) :

      1. 返回指定bean的共享或独立的实例对象

      2. 执行过程:

        1. final String beanName = transformedBeanName(name); : 当存在 bean 的别名与已经实例化的bean name 匹配的时候,返回规范化的beanName

        2. Object sharedInstance = getSingleton(beanName); : 调用 DefaultSingletonBeanRegistry.getSingleton(String beanName,boolean allowEarlyReference)依次从单例对象缓存,单例工厂对象缓存,提前引用单例对象缓存中查找指定的bean,允许提前缓存的bean对象,通常是为了识别以及处理循环依赖的问题;

        3. 我这里的userService 是新创建的bean对象,所以没有被任何一个地方缓存,因此会继续向下;会获取到RootBeanDefinition 对象,调用它的getDependsOn()方法,获取当前bean所依赖的bean对象,确保它们在当前bean初始化之前已经被初始化(如果还是按照以前由对象自身管理自身的依赖对象,那么这一步就变成主动去调用所有对象的初始化方法了,依赖的对象一旦多起来,就会看的头皮发麻)。

        4. 在查找存在依赖bean对象之后,会再反过来确认一遍bean之间的依赖关系,如果反向依赖关系也存在,那说明他们之间形成了环形依赖,会直接抛出异常,说明这种情况是它处理不了的循环依赖。因为根据接下来的步骤:registerDependentBean(dep,beanName)和getBean(dep),注册依赖对象和bean对象,然后获取bean对象,getBean()方法又会调用当前的doGetBean(),因此如果当前bean和依赖bean还存在反向依赖,就会陷入创建bean的死循环了,所以直接抛出异常是对的。

        5. 随后是进行bean类型的判断,singleton,prototype和其他,根据不同的bean类型通过不同的流程创建bean对象;单例bean对象还是会调用DefaultSingletonBeanRegistry.getSingletoon()方法从换从中查找bean对象,这里会先进行bean的创建,再从缓存中获取bean对象:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12

          if (mbd.isSingleton()) {
          sharedInstance = getSingleton(beanName, () -> {
          try {
          return createBean(beanName, mbd, args);
          }
          catch (BeansException ex) {
          ...
          }
          });
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
          }

          getSingleton的第二个参数是实现ObjectFactory的接口,调用的createBean()方法创建bean,最终调用的是AbstractAutowireCapableBeanFactory.createBean()方法,而这个方法我们之前其实提到了,因为它做了一些准备工作之后,就会调用doCreateBean()方法去创建bean对象了

        6. 所以整个过程也就串起来了: (流程图: https://www.processon.com/view/link/5f16ec21f346fb5cdc98e09a)

        7. 整个的getBean()方法调用过程大概就是这样子了


小结:

  • 在ApplicationContext 中,会一次性创建好所有需要的bean对象,从调用getBean()方法开始
  • 存在着几层bean对象的缓存,分别存放着不同类型的bean对象:单例bean,beanName-benFactory 映射,createdBean 对象等,除了第一次会执行bean的创建过程,之后每次都会尝试从这些缓存中获取单例bean
  • 对于单例和多实例的bean对象,创建过程是有很大区别的,多实例bean对象创建后不会缓存,会有明显的前后置方法调用
  • //TODO