Spring refresh函数(3)——Spring Boot finishBeanFactoryInitialization函数

在Spring Boot经过一系列的准备工作后,在finishBeanFactoryInitialization()函数中开始真正地创建Bean。创建Bean的过程是Spring IoC的核心,完成对Bean创建由用户到Spring控制的转移。

以被@Component注解的Bean创建为例。从类AbstractApplicationContext的refresh()函数开始,调用finishBeanFactoryInitialization()。

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

进入函数finishBeanFactoryInitialization()后,直接来到函数的最后一行,调用类DefaultListableBeanFactory中的函数preInstantiateSingletons()实例化所有余下的单例Bean。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    //...略去部分代码...
    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
}

preInstantiateSingletons()函数调用父类AbstractBeanFactory的getBean()方法实例化,走到下面代码的31行,Spring Boot源码中的761行(1.5.7.RELEASE版本)。

@Override
public void preInstantiateSingletons() throws BeansException {
    if (this.logger.isDebugEnabled()) {
      this.logger.debug("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        if (isFactoryBean(beanName)) {
          final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
          boolean isEagerInit;
          if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
            isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
              @Override
              public Boolean run() {
                return ((SmartFactoryBean<?>) factory).isEagerInit();
              }
            }, getAccessControlContext());
          }
          else {
            isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
          }
          if (isEagerInit) {
            getBean(beanName);
          }
        }
        else {
          getBean(beanName);
        }
      }
    }
    //...略去部分代码...
}

getBean()方法调用AbstractBeanFactory类中的doGetBean()方法。这里是Spring Boot实例化Bean的公共逻辑,不仅用户自定义的Bean实例化会调用这个函数,其他的包括系统需要实例化的processors,上下文信息等都共用这里逻辑进行Bean的实例化。

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

doGetBean()方法比较长,会先判断缓存中是否已经存在了实例化的Bean。我们的示例中不存在Bean与Bean依赖关系,首次创建缓存查询返回null,直接创建实例化Bean。Spring设置三级缓存处理Bean的依赖关系,实例化Bean之前还需要先实例化当前Bean所依赖的Bean,另外三级缓存可以解决Bean的循环依赖,关注公众号《 魔法师和ta的南瓜小屋》中其他文章详细介绍。

protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
       //...略去部分代码...
        // Create bean instance.
        if (mbd.isSingleton()) {
          sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
              try {
                return createBean(beanName, mbd, args);
              }
              catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
              }
            }
          });
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
      //...略去部分代码...
    return (T) bean;
}

执行类AbstractAutowireCapableBeanFactory中的createBean()函数。

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    //...略去部分代码...
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

调用类AbstractAutowireCapableBeanFactory中的doCreateBean()函数后,继续调用其createBeanInstance()函数和instantiateBean()函数。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
      throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    mbd.resolvedTargetType = beanType;
    //...略去部分代码...
    return exposedObject;
}
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    //...略去部分代码...
    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
}

类AbstractAutowireCapableBeanFactory中的instantiateBean()函数,使用了一个设计模式——策略模式,把Bean的实例化委托给了一个简单的实例化策略类进行。

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    //...略去部分代码...
     beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
     //...略去部分代码...
}

类SimpleInstantiationStrategy中instantiate()调用类BeanUtils的static方法instantiateClass()进行实例化。

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
    //...略去部分代码...
      return BeanUtils.instantiateClass(constructorToUse);
    //...略去部分代码...
}

BeanUtils.instantiateClass()通过Java反射机制,利用构造函数对Bean进行最终的实例化,生成一个新的Bean。而Bean的类信息是通过BeanDefinition结构获得的。

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
    Assert.notNull(ctor, "Constructor must not be null");
    try {
      ReflectionUtils.makeAccessible(ctor);
      return ctor.newInstance(args);
    }
    catch (InstantiationException ex) {
      throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
    }
    catch (IllegalAccessException ex) {
      throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
    }
    catch (IllegalArgumentException ex) {
      throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
    }
    catch (InvocationTargetException ex) {
      throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335

推荐阅读更多精彩内容