Spring Bean生命周期[1]

319 阅读3分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

bean生命流程

一定会做2件事情:

  • 扫描
  • 创建非懒加载单例bean

所以其实这里一共分为三步:

  • 扫描bean
  • 创建bean
  • 其他事项

第一步 - 扫描bean

这一步对应的是SpringBoot启动步骤的这里:

     context = createApplicationContext();
     //...........
     public AnnotationConfigServletWebServerApplicationContext() {
         this.reader = new AnnotatedBeanDefinitionReader(this);
         this.scanner = new ClassPathBeanDefinitionScanner(this);
     }
  

scanner 如何扫描?

BeanDefinitionRegistry - DefaultListableBeanFactory

为什么使用前者不是后者? - 最小知识原则

scan里。

核心在doScan.

 getMetadataReaderFactory().getMetadataReader(resource)

使用了ASM技术,将class文件处理成可处理的BD

此处必须带有@Component,并且通过了@Conditional的match匹配条件,才能继续。

这里解析完之后,只是把Bean的名称赋给BeanDefinition的beanClass。

这里是个Object,此处赋值是String,后面准备初始化了才会赋值为Class

以下的情况,不能成为Bean:

  • 内部类,抽象类、接口

  • 但如果有被@LookUp修饰的方法,就会被作为Bean注册。

    lookup注解,简单来说就是在单例bean调用prototype的bean时,可以让lookup修饰的方法,每次都返回不同的值

...

  • 处理完之后,会放到BeanFactory里的BeanDefinitionMap里。

第二步 - 初始化非懒加载的单例bean

这一步在context.refresh中的finishBeanFactoryInitialization里的preInstantiateSingletons,实例化单例bean。

在这一步,会将当前为止所有有bd名字记录的BD(beanDefinitionNames中有的),初始化为bean。

对应代码如下:

         for (String beanName : beanNames) {
             RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
             //bd.isAbstract()指的是抽象的BD,而不是抽象的bean的BD
             if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                 if (isFactoryBean(beanName)) {
                     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                     if (bean instanceof FactoryBean) {
                         FactoryBean<?> factory = (FactoryBean<?>) bean;
                         boolean isEagerInit;
                         if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                             isEagerInit = AccessController.doPrivileged(
                                     (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                                     getAccessControlContext());
                         }
                         else {
                             isEagerInit = (factory instanceof SmartFactoryBean &&
                                     ((SmartFactoryBean<?>) factory).isEagerInit());
                         }
                         if (isEagerInit) {
                             getBean(beanName);
                         }
                     }
                 }
                 else {
                     getBean(beanName);
                 }
             }
         }

抽象的BD

抽象的BD指的是BD本身属性是抽象的,而不是抽象的bean的BD。

  • 有什么用?

父子BD中可以用(也可用其他的) 抽象BD来进行继承,这里的继承指的不是类继承,只是父子关系

这两个是父子关系,子BD中没有特殊声明的属性,会从父BD中继承.

在上面这块,子BD会进行:

getMergedLocalBeanDefinition(beanName)

getMergedLocalBeanDefinition - 获取合并后的最终BD

合并BD。

这里会生成一个新的BD,做一个包括继承以及其他关联关系中包括的所有信息的BD,放在mergedBeanDefinitions里。

rootBD:指的是根BD,是最终包括应有的所有信息的BD。

这里的代码最终到这里:

 protected RootBeanDefinition getMergedBeanDefinition(
       String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
       throws BeanDefinitionStoreException {
 ​
    synchronized (this.mergedBeanDefinitions) {
       RootBeanDefinition mbd = null;
       RootBeanDefinition previous = null;
 ​
       // Check with full lock now in order to enforce the same merged instance.
       if (containingBd == null) {
          mbd = this.mergedBeanDefinitions.get(beanName);
       }
 ​
       if (mbd == null || mbd.stale) {
          previous = mbd;
          if (bd.getParentName() == null) {
             // Use copy of given root bean definition.
             if (bd instanceof RootBeanDefinition) {
                mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
             }
             else {
                mbd = new RootBeanDefinition(bd);
             }
          }
          else {
             // Child bean definition: needs to be merged with parent.
             BeanDefinition pbd;
             try {
                String parentBeanName = transformedBeanName(bd.getParentName());
                if (!beanName.equals(parentBeanName)) {
                   pbd = getMergedBeanDefinition(parentBeanName);
                }
                else {
                   BeanFactory parent = getParentBeanFactory();
                   if (parent instanceof ConfigurableBeanFactory) {
                      pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                   }
                   else {
                      throw new NoSuchBeanDefinitionException(parentBeanName,
                            "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                  "': cannot be resolved without a ConfigurableBeanFactory parent");
                   }
                }
             }
             catch (NoSuchBeanDefinitionException ex) {
                throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                      "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
             }
             // Deep copy with overridden values.
             mbd = new RootBeanDefinition(pbd);
             mbd.overrideFrom(bd);
          }
 ​
          // Set default singleton scope, if not configured before.
          if (!StringUtils.hasLength(mbd.getScope())) {
             mbd.setScope(SCOPE_SINGLETON);
          }
 ​
          // A bean contained in a non-singleton bean cannot be a singleton itself.
          // Let's correct this on the fly here, since this might be the result of
          // parent-child merging for the outer bean, in which case the original inner bean
          // definition will not have inherited the merged outer bean's singleton status.
          if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
             mbd.setScope(containingBd.getScope());
          }
 ​
          // Cache the merged bean definition for the time being
          // (it might still get re-merged later on in order to pick up metadata changes)
          if (containingBd == null && isCacheBeanMetadata()) {
             this.mergedBeanDefinitions.put(beanName, mbd);
          }
       }
       if (previous != null) {
          copyRelevantMergedBeanDefinitionCaches(previous, mbd);
       }
       return mbd;
    }
 }

tips:

  • 在这里,会递归地查找整个BD继承树(当然,不是类的继承关系)。

      String parentBeanName = transformedBeanName(bd.getParentName());
                    if (!beanName.equals(parentBeanName)) {
                       pbd = getMergedBeanDefinition(parentBeanName);
                    }
    
  • 在这里,会做一个合并。

                         mbd = new RootBeanDefinition(pbd);
                         mbd.overrideFrom(bd);
    
  • 随后,存起来:

                     if (containingBd == null && isCacheBeanMetadata()) {
                         this.mergedBeanDefinitions.put(beanName, mbd);
                     }
    

    接下去会判断是否是工厂bean,我们留到下一期再分析。