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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 【小家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(调用一些初始化方法)


相关文章
|
15天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
70 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
1月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
1月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
83 1
|
1月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
40 1
|
Java 应用服务中间件 数据库连接
Spring全家桶之Spring篇深度分析(一)
Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
Spring全家桶之Spring篇深度分析(一)
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
167 2
|
13天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
26 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
9天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
21 2

相关产品

  • 容器服务Kubernetes版
  • 下一篇
    无影云桌面