spring何时完成bean创建|8月更文挑战

86 阅读2分钟

思考:单例bean何时完成创建?原型Bean何时完成创建?

public class Spring {
    public static void main(String[] args) {
        // 1. 加载配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        // 2. 从容器中获取 bean
        Student student = context.getBean("student", Student.class);
    }
}

第一次调用getBean: spring在加载配置文件时,会调用doGetBean(),将单例bean全部加载到单例池中。而原型bean会在第二次调用时创建。【创建Bean】
第二次调用getBean: 获取bean;延迟创建原型bean【创建Bean、获取Bean】

创建bean,获取bean,最终的工作实现都是doGetBean(),那么它具体做了哪些工作呢?

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    // 1. 获取beanName ==> 如果name有&,截掉之后再返回beanName。否则直接返回beanName
    String beanName = this.transformedBeanName(name);
    // 2. 根据 beanName 从 单例池 中获取 单例bean
    Object sharedInstance = this.getSingleton(beanName);
    Object beanInstance;
    if (sharedInstance != null && args == null) {
        beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
        // 创建bean,接下来看看spring如何创建bean?
        try {
            // 1. 根据 beanName 获取 RootBeanDefinition (bean定义信息) 
            // <bean id="" class=""></bean>
            RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            // 2. 检查 BeanDefinition 是否为 抽象类
            this.checkMergedBeanDefinition(mbd, beanName, args);
            // 3. 获取 类 依赖的其它类 <bean id="" class="" depends-on="xx"></bean>
            String[] dependsOn = mbd.getDependsOn();
            // 3.1 如果存在 依赖bean,必须先实例化 依赖bean
            if (dependsOn != null) {
               for (String dep : dependsOn) {
                  registerDependentBean(dep, beanName);
                  getBean(dep);
            }
            // 4.1 创建单例bean:默认 RootBeanDefinition 的 scope="singleton"
            if (mbd.isSingleton()) {
                sharedInstance = this.getSingleton(beanName, () -> {
                    try {
                        return this.createBean(beanName, mbd, args);
                    } catch (BeansException ex) {
                        this.destroySingleton(beanName);
                        throw ex;
                    }
                });
                beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
            // 4.2 创建原型bean: RootBeanDefinition 的 scope="prototype"
                Object prototypeInstance = null;
                try {
                    this.beforePrototypeCreation(beanName);
                    prototypeInstance = this.createBean(beanName, mbd, args);
                } finally {
                    this.afterPrototypeCreation(beanName);
                }

                beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
               // 4.3 创建bean:其它scope类型,比如request、session等
            }
    }
    // 返回 bean
    return this.adaptBeanInstance(name, beanInstance, requiredType);
}

从上面代码可以看出,真正创建bean的方法是createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   RootBeanDefinition mbdToUse = mbd;

   // Make sure bean class is actually resolved at this point, and
   // clone the bean definition in case of a dynamically resolved Class
   // which cannot be stored in the shared merged bean definition.
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // Prepare method overrides.
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}