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


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

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

    1. @Override
    2. public void preInstantiateSingletons() throws BeansException {
    3. //该方法先复制一份BeanDefinition名称列表,为了防止在初始化过程中有新的BeanDefinition被注册,
    4. //从而导致遍历过程中的并发修改异常
    5. List beanNames = new ArrayList<>(this.beanDefinitionNames);
    6. //对于每个非抽象、单例且非懒加载的 BeanDefinition,如果它是一个 FactoryBean,
    7. //则获取 FactoryBean 的实例,如果 FactoryBean 实现了 `SmartFactoryBean` 接口,
    8. //则调用 `isEagerInit` 方法判断是否需要预先实例化,默认为需要预先实例化。
    9. //如果该 Bean 需要预先实例化,则调用 `getBean` 方法进行实例化。
    10. for (String beanName : beanNames) {
    11. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    12. // 不是抽象类&&是单例&&不是懒加载
    13. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    14. if (isFactoryBean(beanName)) {
    15. Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    16. if (bean instanceof FactoryBean) {
    17. FactoryBean factory = (FactoryBean) bean;
    18. boolean isEagerInit;
    19. if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    20. isEagerInit = AccessController.doPrivileged(
    21. (PrivilegedAction) ((SmartFactoryBean) factory)::isEagerInit,
    22. getAccessControlContext());
    23. }
    24. else {
    25. isEagerInit = (factory instanceof SmartFactoryBean &&
    26. ((SmartFactoryBean) factory).isEagerInit());
    27. }
    28. if (isEagerInit) {
    29. getBean(beanName);
    30. }
    31. }
    32. }
    33. else {
    34. // 这里就是普通单例Bean正式初始化了
    35. getBean(beanName);
    36. }
    37. }
    38. }
    39. //对于每个实现了SmartInitializingSingleton接口的单例Bean,调用其afterSingletonsInstantiated方法
    40. // 执行时机是在bean的生命周期最后,即在bean完成实例化、属性注入、相关初始化操作后
    41. for (String beanName : beanNames) {
    42. Object singletonInstance = getSingleton(beanName);
    43. if (singletonInstance instanceof SmartInitializingSingleton) {
    44. SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    45. if (System.getSecurityManager() != null) {
    46. AccessController.doPrivileged((PrivilegedAction) () -> {
    47. smartSingleton.afterSingletonsInstantiated();
    48. return null;
    49. }, getAccessControlContext());
    50. }
    51. else {
    52. // 比如:ScheduledAnnotationBeanPostProcessor CacheAspectSupport MBeanExporter等等
    53. smartSingleton.afterSingletonsInstantiated();
    54. }
    55. }
    56. }
    57. }
    58.         对该方法可简单总结为以下三点:

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

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

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

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

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

      1. @Override
      2. protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      3. throws BeanCreationException {
      4. RootBeanDefinition mbdToUse = mbd;
      5. //确保实际解析了bean Class类型
      6. //并在动态解析类的情况下克隆beanDefinition,因为动态解析的类无法存储在共享的合并beanDefinition中
      7. Class resolvedClass = resolveBeanClass(mbd, beanName);
      8. if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      9. mbdToUse = new RootBeanDefinition(mbd);
      10. mbdToUse.setBeanClass(resolvedClass);
      11. }
      12. // Prepare method overrides.
      13. try {
      14. // 预先标记没有重载的方法,以避免参数类型检查的开销
      15. mbdToUse.prepareMethodOverrides();
      16. }
      17. catch (BeanDefinitionValidationException ex) {
      18. throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
      19. beanName, "Validation of method overrides failed", ex);
      20. }
      21. try {
      22. // 实例化前阶段:让BeanPostProcessors有机会返回代理而不是目标bean实例
      23. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      24. if (bean != null) {
      25. return bean;
      26. }
      27. }
      28. catch (Throwable ex) {
      29. throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
      30. "BeanPostProcessor before instantiation of bean failed", ex);
      31. }
      32. try {
      33. // 创建bean真正"干实事"方法
      34. Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      35. if (logger.isTraceEnabled()) {
      36. logger.trace("Finished creating instance of bean '" + beanName + "'");
      37. }
      38. return beanInstance;
      39. }
      40. catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      41. // A previously detected exception with proper bean creation context already,
      42. // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      43. throw ex;
      44. }
      45. catch (Throwable ex) {
      46. throw new BeanCreationException(
      47. mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
      48. }
      49. }

              在真正实例化之前,如果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源码及注释如下:

      1. // 使用适当的实例化策略为指定的bean创建一个新实例:工厂方法、构造函数自动装配或简单实例化
      2. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
      3. // Make sure bean class is actually resolved at this point.
      4. // 获取bean的Class对象
      5. Class beanClass = resolveBeanClass(mbd, beanName);
      6. if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      7. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
      8. "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
      9. }
      10. // 通过bd中提供的instanceSupplier来获取一个对象
      11. // 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
      12. Supplier instanceSupplier = mbd.getInstanceSupplier();
      13. if (instanceSupplier != null) {
      14. return obtainFromSupplier(instanceSupplier, beanName);
      15. }
      16. // 如果工厂方法不为null,则使用工厂方法初始化策略
      17. // bd中提供了factoryMethodsName属性,那么要使用工厂方法的方法来创建对象
      18. // 工厂方法又会区分静态工厂方法跟实例工厂方法
      19. if (mbd.getFactoryMethodName() != null) {
      20. // 如果使用了工厂方法,则调用工厂方法创建bean实例。@Bean注解创建的实例会进入这里
      21. return instantiateUsingFactoryMethod(beanName, mbd, args);
      22. }
      23. // Shortcut when re-creating the same bean...
      24. // 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了
      25. // 是否推断过构造函数
      26. boolean resolved = false;
      27. // 构造函数是否需要进行注入
      28. boolean autowireNecessary = false;
      29. if (args == null) {
      30. synchronized (mbd.constructorArgumentLock) {
      31. // 一个类里面有多个构造函数,每个构造函数都有不同的参数,所以调用前需根据参数锁定要调用
      32. // 的构造函数或工厂方法
      33. if (mbd.resolvedConstructorOrFactoryMethod != null) {
      34. resolved = true;
      35. autowireNecessary = mbd.constructorArgumentsResolved;
      36. }
      37. }
      38. }
      39. // 如果已经解析过则使用解析好的构造函数方法,不需要再次锁定
      40. if (resolved) {
      41. if (autowireNecessary) {
      42. // 构造函数自动注入
      43. return autowireConstructor(beanName, mbd, null, null);
      44. }
      45. else {
      46. // 使用默认构造函数进行构造
      47. return instantiateBean(beanName, mbd);
      48. }
      49. }
      50. // Candidate constructors for autowiring?
      51. // 需要根据参数解析构造函数
      52. Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
      53. if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
      54. mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      55. // 构造函数自动注入
      56. return autowireConstructor(beanName, mbd, ctors, args);
      57. }
      58. // Preferred constructors for default construction?
      59. // 获取首选构造函数,作为默认构造器
      60. ctors = mbd.getPreferredConstructors();
      61. if (ctors != null) {
      62. return autowireConstructor(beanName, mbd, ctors, null);
      63. }
      64. // No special handling: simply use no-arg constructor.
      65. // 没有什么特殊的处理:简单使用无参构造方法
      66. return instantiateBean(beanName, mbd);
      67. }

              总结如下:

      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。

    59. 相关阅读:
      第十五届蓝桥杯省赛C/C++大学B组真题及赛后总结
      Modbus网关实现设备之间的相互通信和数据共享
      网站:推荐几款好用的在线短链生成工具
      计算机毕业设计JAVA二手物品置换平台mybatis+源码+调试部署+系统+数据库+lw
      【MATLAB】MVMD_ MFE_SVM_LSTM 神经网络时序预测算法
      linux中git的使用
      【空间-光谱联合注意网络:多时相遥感图像】
      为何Http3没有Http2快速重置攻击?
      Transformer对接公司需求的调研报告
      Java基础面试题精选:深入探讨哈希表、链表和接口等
    60. 原文地址:https://blog.csdn.net/zhangweiocp/article/details/134385145