Spring IOC - Bean的生命周期之实例化

在Spring启动流程文章中讲到,容器的初始化是从refresh方法开始的,其在初始化的过程中会调用finishBeanFactoryInitialization方法。

而在该方法中则会调用DefaultListableBeanFactory#preInstantiateSingletons方法,该方法的核心作用是初始化非延迟加载的Bean,且提供了两个扩展点。源码及注释如下:

java 复制代码
@Override
public void preInstantiateSingletons() throws BeansException {

   //该方法先复制一份BeanDefinition名称列表,为了防止在初始化过程中有新的BeanDefinition被注册,
   //从而导致遍历过程中的并发修改异常
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   //对于每个非抽象、单例且非懒加载的 BeanDefinition,如果它是一个 FactoryBean,
   //则获取 FactoryBean 的实例,如果 FactoryBean 实现了 `SmartFactoryBean` 接口,
   //则调用 `isEagerInit` 方法判断是否需要预先实例化,默认为需要预先实例化。
   //如果该 Bean 需要预先实例化,则调用 `getBean` 方法进行实例化。
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // 不是抽象类&&是单例&&不是懒加载
      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 {
            // 这里就是普通单例Bean正式初始化了
            getBean(beanName);
         }
      }
   }

   //对于每个实现了SmartInitializingSingleton接口的单例Bean,调用其afterSingletonsInstantiated方法
   // 执行时机是在bean的生命周期最后,即在bean完成实例化、属性注入、相关初始化操作后
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            // 比如:ScheduledAnnotationBeanPostProcessor CacheAspectSupport  MBeanExporter等等
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}

对该方法可简单总结为以下三点:

  1. 对于实现了SmartFactoryBean的子类,如果isEagerInit(立即初始化)返回true,则对本是懒加载的getObject对象立即初始化;

  2. 否则,正常调用getBean方法开始bean的生命周期;

  3. 在bean的生命周期处理结束后,对实现了SmartInitializingSingleton接口的单例Bean,调用其afterSingletonsInstantiated方法

继续就是"干实事"的方法:AbstractBeanFactory#doGetBean,其逻辑流程图如下所示:

其中创建Bean的核心方法为AbstractAutowireCapableBeanFactory#createBean,源码及注释如下:

java 复制代码
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   RootBeanDefinition mbdToUse = mbd;
   
   //确保实际解析了bean Class类型
   //并在动态解析类的情况下克隆beanDefinition,因为动态解析的类无法存储在共享的合并beanDefinition中
   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 {
      // 实例化前阶段:让BeanPostProcessors有机会返回代理而不是目标bean实例
      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 {
      // 创建bean真正"干实事"方法
      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);
   }
}

在真正实例化之前,如果bean实现了InstantiationAwareBeanPostProcessor接口,则会调用其postProcessBeforeInstantiation方法,这就是bean生命周期的实例化前阶段。该接口提供的核心方法及作用如下表所示:

|--------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 方法名称 | 作用阶段 | 作用 |
| postProcessBeforeInstantiation | 实例化前 | 该方法传入目标Bean类型与BeanName;该方法可以返回一个该Bean类型的对象,或对该Bean的一个代理对象; 当该方法返回了实例化对象后,后续的所有Bean实例化与初始化的动作将不再进行。只会调用后续的BeanPostProcessor#postProcessAfterInnitialization方法 |
| postProcessAfterInstantiation | 实例化后 | 该方法传入还没有装配属性的Bean对象以及BeanName 如果该方法返回false,则将跳过后续的属性装配动作,一般应该返回true |
| postProcessProperties | 实例化后 属性填充前 | 该方法传入在配置期间所配的PropertyValues以及BeanName 该方法返回的PropertyValues将最终装配到Bean对象中 |

接下来是doCreateBean方法,其逻辑流程图如下:

  1. 先检查instanceWrapper变量是不是null,这里一般是null,除非当前正在创建的Bean在factoryBeanInstanceCache中存在这个是保存还没创建完成的FactoryBean的集合。

  2. 调用createBeanInstance方法实例化Bean,这个方法在后面会讲解

  3. 如果当前RootBeanDefinition对象还没有调用过实现了的MergedBeanDefinitionPostProcessor接口的方法,则会进行调用

  4. 当满足以下三点 (1)是单例Bean (2)尝试解析bean之间的循环引用 (3)bean目前正在创建中 则会进一步检查是否实现了SmartInstantiationAwareBeanPostProcessor接口如果实现了则调用是实现的getEarlyBeanReference方法

  5. 调用populateBean方法进行属性填充

  6. 调用initializeBean方法对Bean进行初始化

关键方法AbstractAutowireCapableBeanFactory#createBeanInstance源码及注释如下:

java 复制代码
// 使用适当的实例化策略为指定的bean创建一个新实例:工厂方法、构造函数自动装配或简单实例化
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   // 获取bean的Class对象
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }

   // 通过bd中提供的instanceSupplier来获取一个对象
   // 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   // 如果工厂方法不为null,则使用工厂方法初始化策略
   // bd中提供了factoryMethodsName属性,那么要使用工厂方法的方法来创建对象
   // 工厂方法又会区分静态工厂方法跟实例工厂方法
   if (mbd.getFactoryMethodName() != null) {
      // 如果使用了工厂方法,则调用工厂方法创建bean实例。@Bean注解创建的实例会进入这里
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   // 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了
   // 是否推断过构造函数
   boolean resolved = false;
   // 构造函数是否需要进行注入
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         // 一个类里面有多个构造函数,每个构造函数都有不同的参数,所以调用前需根据参数锁定要调用
         // 的构造函数或工厂方法
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   // 如果已经解析过则使用解析好的构造函数方法,不需要再次锁定
   if (resolved) {
      if (autowireNecessary) {
         // 构造函数自动注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 使用默认构造函数进行构造
         return instantiateBean(beanName, mbd);
      }
   }

   // Candidate constructors for autowiring?
   // 需要根据参数解析构造函数
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      // 构造函数自动注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // Preferred constructors for default construction?
   // 获取首选构造函数,作为默认构造器
   ctors = mbd.getPreferredConstructors();
   if (ctors != null) {
      return autowireConstructor(beanName, mbd, ctors, null);
   }

   // No special handling: simply use no-arg constructor.
   // 没有什么特殊的处理:简单使用无参构造方法
   return instantiateBean(beanName, mbd);
}

总结如下:

  1. 先检查Class是否已经关联了,并且对应的修饰符是否是public的

  2. 如果用户定义了Bean实例化的函数,则调用并返回

  3. 如果当前Bean实现了FactoryBean接口则调用对应的FactoryBean接口的getObject方法

  4. 根据getBean时候是否传入构造参数进行处理

  • 4.1 如果没有传入构造参数,则检查是否存在已经缓存的无参构造器,有则使用构造器直接创建,没有就会调用instantiateBean方法先获取实例化的策略默认是CglibSubclassingInstantiationStrategy,然后实例化Bean。最后返回

  • 4.2 如果传入了构造参数,则会先检查是否实现了SmartInstantiationAwareBeanPostProcessor接口,如果实现了会调用determineCandidateConstructors获取返回的候选构造器。

  • 4.3 检查4个条件是否满足一个 (1)构造器不为null, (2)从RootBeanDefinition中获取到的关联的注入方式是构造器注入(没有构造参数就是setter注入,有则是构造器注入) (3)含有构造参数 (4)getBean方法传入构造参数不是空 满足其中一个则会调用返回的候选构造器实例化Bean并返回,如果都不满足,则会根据构造参数选则合适的有参构造器然后实例化Bean并返回

  • 如果上面都没有合适的构造器,则直接使用无参构造器创建并返回Bean。

相关推荐
刘一说4 分钟前
资深Java工程师的面试题目(五)微服务
java·微服务·面试
boy快快长大8 分钟前
【JUC】显示锁
java
bobz96510 分钟前
nodejs 简单了解
后端
bobz96512 分钟前
想用 nodejs 启动一个 web 服务,但是遇到了 python2 的问题
后端
强哥叨逼叨18 分钟前
Postgres 杀疯了,堪称 “六边形战士”,还要 Redis 干啥?
后端
写bug写bug28 分钟前
Spring Cloud中的@LoadBalanced注解实现原理
java·后端·spring cloud
青木川崎32 分钟前
java获取天气信息
java
十月不到底36 分钟前
在 Tomcat 中通过 web.xml 配置缓存控制响应头
后端
HoroMin37 分钟前
在Spring Boot中自定义JSON返回日期格式的指南
java·开发语言·spring boot·注解
涡能增压发动积37 分钟前
实践出真知,大模型也会犯糊涂
后端