【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...)(上)

简介: 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...)(上)

前言


在前面分析Spring IoC容器的时候,贯穿全文的一个概念:Bean定义信息。它是Spring容器的一个核心概念,那么本文就深入分析一下BeanDefinition这个接口(类)。


Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。

不管是是通过xml配置文件的\<Bean>标签,还是通过注解配置的@Bean,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作


从上可知BeanDefinition这个接口对Spring IoC容器的重要之处,所以了解好了它(以及子类),能让我们更大视野的来看Spring管理Bean的一个过程,也能透过现象看本质。


透彻理解Spring容器是打开Spring Boot大门的一把钥匙


下面用一个非常形象的比喻,来形容Spring IoC容器和BeanDefinition之前的关系。


比喻:BeanFactory和BeanDefinition


Spring IoC容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。

IoC容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。

那么问题来了,作为餐馆,想要做出菜肴,得知道菜的原料和菜谱。同样地,IoC容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。 BeanDefinition对象就承担了这个责任

容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的 所有 必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等(所以BeanDefinition就好比做菜的原料)


需要说明的一点是:加入你是自己直接通过 SingletonBeanRegistry#registerSingleton向容器手动注入Bean的,那么就不会存在这份Bean定义信息的,这点需要注意。

Spring内部有不少这样的例子(因为这种Bean非常简单,根本不需要定义信息):

beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());

beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);

bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);

bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap));


现在可以开始做菜了吗?其实还不行,因为还没有菜谱(不知道做什么菜,怎么做~)

BeanDefinitionRegistry和 BeanFactory就是这份菜谱,BeanDefinitionRegistry抽象出bean的注册逻辑,而BeanFactory则抽象出了bean的管理逻辑

各个BeanFactory的实现类就具体承担了bean的注册以及管理工作


DefaultListableBeanFactory作为一个比较通用的BeanFactory实现,它同时也实现了BeanDefinitionRegistry接口,因此它就承担了Bean的注册管理工作


最后我们总结一下比喻关系:

  1. Spring IoC容器:餐馆(服务员)
  2. BeanDefinitionRegistry和 BeanFactory:菜谱
  3. BeanDefinitionRegistry:抽象出来的,向菜谱里注册菜(的管理器)
  4. BeanFactory:抽象出来的,管理这些菜谱(的管理器)
  5. BeanDefinition:原料(做菜所需要的原料)
  6. DefaultListableBeanFactory:具体实施者(具体注册菜谱、做菜的实施者)
  7. 依赖注入的使用者:客户(进店吃饭的人)


BeanDefinition源码分析


总体的 Java Class Diagrams 图:

image.png


因为它继承了AttributeAccessor,和BeanMetadataElement,所以我们先有必要来了解下这两个接口:


AttributeAccessor:定义了对对象元数据访问的抽象接口


// 接口都比较简单  就是定义了对对象属性的一些访问方法
//说明它可以持有Bean元数据元素,作用是可以持有XML文件的一个bean标签对应的Object(或者@Configuration元配置对象)
public interface AttributeAccessor {
  void setAttribute(String name, @Nullable Object value);
  @Nullable
  Object getAttribute(String name);
  @Nullable
  Object removeAttribute(String name);
  boolean hasAttribute(String name);
  String[] attributeNames();
}

AttributeAccessorSupport是唯一抽象实现,内部基于LinkedHashMap实现了所有的接口,供其他子类继承使用 主要针对属性CRUD操作


BeanMetadataElement:具有访问source(配置源)的能力


这个方法在@Configuration中使用较多,因为它会被代理

//接口提供了一个getResource()方法,用来传输一个可配置的源对象。
public interface BeanMetadataElement {
  /**
   * Return the configuration source {@code Object} for this metadata element
   * (may be {@code null}).
   * 返回元数据元素配置元对象
   */
  @Nullable
  Object getSource();
}

BeanDefinition:定义了Bean的各种信息


一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。


BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor

例如PropertyPlaceHolderConfigure 能够检索并修改属性值和别的bean的元数据

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
  // 单例Bean还是原型Bean
  String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
  String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
  // Bean角色
  int ROLE_APPLICATION = 0; //应用程序重要组成部分
  int ROLE_SUPPORT = 1; //做为大量配置的一部分(支持、扩展类)  实际上就是说,我这个Bean是用户的,是从配置文件中过来的。
  int ROLE_INFRASTRUCTURE = 2; //指内部工作的基础构造  实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系
  // Modifiable attributes
  //parent definition(若存在父类的话,就设置进去)
  void setParentName(@Nullable String parentName);
  @Nullable
  String getParentName();
  // 指定Class类型。需要注意的是该类型还有可能被改变在Bean post-processing阶段
  // 若是getFactoryBeanName  getFactoryMethodName这种情况下会改变
  void setBeanClassName(@Nullable String beanClassName);
  @Nullable
  String getBeanClassName();
  //SCOPE_SINGLETON或者SCOPE_PROTOTYPE两种
  void setScope(@Nullable String scope);
  @Nullable
  String getScope();
  // @Lazy 是否需要懒加载(默认都是立马加载的)
  void setLazyInit(boolean lazyInit);
  boolean isLazyInit();
  // 此Bean定义需要依赖的Bean(显然可以有多个)
  void setDependsOn(@Nullable String... dependsOn);
  @Nullable
  String[] getDependsOn();
  // 这个Bean是否允许被自动注入到别的地方去(默认都是被允许的)
  // 注意:此标志只影响按类型装配,不影响byName的注入方式的~~~~
  void setAutowireCandidate(boolean autowireCandidate);
  boolean isAutowireCandidate();
  // 是否是首选的  @Primary
  void setPrimary(boolean primary);
  boolean isPrimary();
  // 指定使用的工厂Bean(若存在)的名称~
  void setFactoryBeanName(@Nullable String factoryBeanName);
  @Nullable
  String getFactoryBeanName();
  //指定工厂方法~
  void setFactoryMethodName(@Nullable String factoryMethodName);
  @Nullable
  String getFactoryMethodName();
  // 获取此Bean的构造函数参数值们  ConstructorArgumentValues:持有构造函数们的 
  // 绝大多数情况下是空对象 new ConstructorArgumentValues出来的一个对象
  // 当我们Scan实例化Bean的时候,可能用到它的非空构造,这里就会有对应的值了,然后后面就会再依赖注入了
  ConstructorArgumentValues getConstructorArgumentValues();
  default boolean hasConstructorArgumentValues() {
    return !getConstructorArgumentValues().isEmpty();
  }
  // 获取普通属性集合~~~~
  MutablePropertyValues getPropertyValues();
  default boolean hasPropertyValues() {
    return !getPropertyValues().isEmpty();
  }
  // Read-only attributes
  boolean isSingleton();
  boolean isPrototype();
  boolean isAbstract();
  // 对应上面的role的值
  int getRole();
  //@Description
  @Nullable
  String getDescription();
  // 返回该Bean定义来自于的资源的描述(用于在出现错误时显示上下文)
  @Nullable
  String getResourceDescription();
  //返回原始BeanDefinition,如果没有则返回@null
  // 若这个Bean定义被代理、修饰过  这个方法可以返回原始的
  @Nullable
  BeanDefinition getOriginatingBeanDefinition();
}

抽象实现、实现类们。上面已经画出了一些类的结构图,下面一个个来看


子接口:AnnotatedBeanDefinition


public interface AnnotatedBeanDefinition extends BeanDefinition {
  //获取该bean definition的注解元数据
  AnnotationMetadata getMetadata();
  //@since 4.1.1
  //Obtain metadata for this bean definition's factory method(如果不存在就返回null)
  @Nullable
  MethodMetadata getFactoryMethodMetadata();
}


AnnotationMetadata定义了访问特定类的注解的抽象接口,它不需要加载该类即可访问


该注解Bean定义旗下三大实现类:ScannedGenericBeanDefinition、ConfigurationClassBeanDefinition、AnnotatedGenericBeanDefinition


相关文章
|
9月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
9月前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
910 6
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
302 1
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
389 18
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
负载均衡 Java API
基于 Spring Cloud 的微服务架构分析
Spring Cloud 是一个基于 Spring Boot 的微服务框架,提供全套分布式系统解决方案。它整合了 Netflix、Zookeeper 等成熟技术,通过简化配置和开发流程,支持服务发现(Eureka)、负载均衡(Ribbon)、断路器(Hystrix)、API网关(Zuul)、配置管理(Config)等功能。此外,Spring Cloud 还兼容 Nacos、Consul、Etcd 等注册中心,满足不同场景需求。其核心组件如 Feign 和 Stream,进一步增强了服务调用与消息处理能力,为开发者提供了一站式微服务开发工具包。
1013 0
|
12月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1416 0
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1310 0
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
576 0
|
9月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
633 4