【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)(中)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)(中)

createBeanInstance


  protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    // 如果不为null,并且还不是public的访问权限 并且还nonPublicAccessAllowed为false 那就抛异常吧
    // 题外话:nonPublicAccessAllowed为true的情况下(默认值),即使你不是public的也ok
    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());
    }
    // 你可以自己通过Supplier来创建Bean,最终交给obtainFromSupplier包装成BeanWrapper
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
    }
    //通过工厂方法创建 支持工厂方法方式创建Bean
    if (mbd.getFactoryMethodName() != null)  {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // Shortcut when re-creating the same bean...
    //一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
    //在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
        if (mbd.resolvedConstructorOrFactoryMethod != null) {
          resolved = true;
          autowireNecessary = mbd.constructorArgumentsResolved;
        }
      }
    }
    // 首次进入,resolved为false。
    // 说一下:ConstructorResolver,就是找到合适的构造器给你去实例化一个Bean(会结合Spring容器进行一起解析)
    if (resolved) {
      if (autowireNecessary) {
        return autowireConstructor(beanName, mbd, null, null);
      }
      else {
        return instantiateBean(beanName, mbd);
      }
    }
    // Need to determine the constructor...
    // 执行BeanPostProcesso#determineCandidateConstructors 自己去决定使用哪个构造器,可能会返回一批构造器哟  
    // 这里我们很熟悉的`AutowiredAnnotationBeanPostProcessor`就实现了这个方法,可以智能去找出一个合适的构造器.
    // 这里需要注意了,因为我们的Child的属性HelloService里并没有书写@Autowired属性,所以这里最终的返回结果是null================这个需要注意Spring的处理(空构造就不用交给autowireConstructor处理了,自己直接new吧)
    // 需要注意的是:若我们自己写了一个构造    public Child(HelloService helloService) {  this.helloService = helloService; } 那么它就会拿到,然后走下面让Spring执行构造器的注入的
    // 旁白:如果你只有空构造,那就直接instantiateBean,否则会自动去走Spring的构造器注入的逻辑
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      return autowireConstructor(beanName, mbd, ctors, args);
    }
    // No special handling: simply use no-arg constructor.
    // 所以我们当前的Child,只有空构造器,所以就只能走这里啦
    // 这个方法的逻辑比较简单,我就不贴了。主要是用InstantiationStrategy策略器进行实例化,至于它是什么东东?文末的时候我会解释的
    return instantiateBean(beanName, mbd);
  }


该方法执行完成之后,我们对象就被创建了,但仅仅还只是创建好哦。下面继续看:


populateBean populate:居住于; 生活于; 大致意思就是给Bean的各个属性赋值


  protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
      if (mbd.hasPropertyValues()) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
        // Skip property population phase for null instance.
        return;
      }
    }
    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;
    // 因为已经实例化了,对象已经创建了,所以这里立马执行了InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation方法
    // 单反只有其中一个返回了false,相当于告诉容器我都处理好了,那么后面的赋值操作就Spring容器就不再处理了
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
          }
        }
      }
    }
    if (!continueWithPropertyPopulation) {
      return;
    }
    //以对象的方式存储健值对,比存储在map会更加灵活
    //PropertyValues  是用来管理PropertyValue的  一般情况下为null
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // 那么接下来,就开始干正事了~~~~
    // 这里需要注意的是:我们知道上面我们自己传进来的是byType,所以这个的if是能够进来的,最终能够定位autowireByType让它去实现注入功能。
    //所以我们的helloService字段要不要@Autowired要不要无所谓(要了也只是重复操作而已,但是我建议显示的指明吧)
    //但是被Spring扫描Scan管理的Bean们(或者其余Bean),如果你想要给他字段注入属性值,必须必须使用@Autowired注解,从而交给后置处理器AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues这个方法去处理
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      // 按类型自动装配。一般都会走这里,通过类型的匹配,来给属性赋值,实现注入
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        // 它的步骤相对简单:显示BeanUtils.getWriteMethodParameter(pd)拿到set方法(所以,这里需要注意,若没有set方法,这里是注入不进去的,这个没@Autowired强大)
        // 然后去解析去容器里面找对应的依赖,也是resolveDependency方法(最终由DefaultListableBeanFactory去实现的)
        // 这里需要注意:注入的时候isSimpleProperty不会被注入的(包括基本数据类型、Integer、Long。。。
        //甚至还包括Enum、CharSequence(显然就包含了Spring)、Number、Date、URI、URL、Locale、Class等等)
        // 但是,但是,但是标注@Autowired是能够注入的哦,哪怕是String、Integer等等
        // 标注了@Autowired,没有找到反倒为报错 No qualifying bean of type 'java.lang.String' 。。。注意这些区别
        autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
    }
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (hasInstAwareBpps || needsDepCheck) {
      if (pvs == null) {
        pvs = mbd.getPropertyValues();
      }
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
        // 开始执行InstantiationAwareBeanPostProcessor#postProcessPropertyValues
        // 这里主要施工的又是我们大名鼎鼎的AutowiredAnnotationBeanPostProcessor它了,他会根据所有标注有@Autpwired注解地方,执行注入(非常重要)
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
          if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvs == null) {
              return;
            }
          }
        }
      }
      if (needsDepCheck) {
        checkDependencies(beanName, mbd, filteredPds, pvs);
      }
    }
    //applyPropertyValues和PropertyValues密切相关,在后面相关专题在详细讲解  会回到这里的,持续关注~
    // 作用:Apply the given property values, resolving any runtime references
    if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
    }
  }


至此,一个Bean的实例化、初始化操作可以完成了一大部分了(各字段、属性的赋值也都已经ok了嘛~),那么还剩下一些收尾工作:比如init方法、post-construct方法之类的,就交给

initializeBean 初始化Bean(调用一些初始化方法)


相关文章
|
14天前
|
人工智能 边缘计算 运维
容器化浪潮下的AI赋能:智能化运维与创新应用
近年来,容器技术以其轻量、高效、可移植的特性成为云原生时代的基石,推动应用开发和部署方式革新。随着容器化应用规模扩大,传统运维手段逐渐力不从心。AI技术的引入为容器化生态带来新活力,实现智能监控、自动化故障诊断与修复及智能资源调度,提升运维效率和可靠性。同时,AI驱动容器化创新应用,如模型训练、边缘计算和Serverless AI服务,带来更多可能性。未来,AI与容器技术的融合将更加紧密,推动更智能、高效的运维平台和丰富的创新应用场景,助力数字化转型。
|
3月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
3月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
89 6
|
3月前
|
Java 数据库 数据安全/隐私保护
轻松掌握Spring依赖注入:打造你的登录验证系统
本文以轻松活泼的风格,带领读者走进Spring框架中的依赖注入和登录验证的世界。通过详细的步骤和代码示例,我们从DAO层的创建到Service层的实现,再到Spring配置文件的编写,最后通过测试类验证功能,一步步构建了一个简单的登录验证系统。文章不仅提供了实用的技术指导,还以口语化和生动的语言,让学习变得不再枯燥。
67 2
|
3月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
57 1
|
4月前
|
运维 持续交付 虚拟化
深入解析Docker容器化技术的核心原理
深入解析Docker容器化技术的核心原理
92 1
|
5月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
5月前
|
存储 监控 Shell
docker的底层原理二:容器运行时环境
本文深入探讨了Docker容器运行时环境的关键技术,包括命名空间、控制组、联合文件系统、容器运行时以及分离的进程树,这些技术共同确保了容器的隔离性、资源控制和可移植性。
82 5
|
6月前
|
Kubernetes Linux 虚拟化
一文详解容器技术简介和基本原理
本文全面阐述了容器技术的发展历程、关键技术、架构和当前的行业生态,特别是容器技术在云环境中的应用和演进。
|
7月前
|
XML Java 数据格式
Spring5入门到实战------8、IOC容器-Bean管理注解方式
这篇文章详细介绍了Spring5框架中使用注解进行Bean管理的方法,包括创建Bean的注解、自动装配和属性注入的注解,以及如何用配置类替代XML配置文件实现完全注解开发。
Spring5入门到实战------8、IOC容器-Bean管理注解方式

相关产品

  • 容器服务Kubernetes版