Spring原理学习系列之六:IOC原理之BeanDefinition注册

简介: 本文主要介绍了BeanDefinition以及BeanDefinition的注册,BeanDefinition是Spring处理Bean的统一的数据结构,BeanDefinitionRegistry的实现类对BeanDefinition完成了注册操作,注册最终结果保存在beanDefinitionMap这个ConcurrentHashMap中。今天的内容就到这里了,我们下次再会了哦。

引言

在上一篇文章中,我们大致介绍了Bean创建、Bean加载的流程,但是由于文章篇幅所限,不能事无巨细的进行详细介绍。后续本系列的文章将对这部分的内容进行庖丁解牛,尽可能的将IOC中比较重要的细节说明清楚,以便于自己以及花时间阅读本文的读者可以加深对于Spring IOC的深入理解。

  • BeanDefinition
  • BeanDefinitionRegistry
  • 总结


一、BeanDefinition

纳尼,你还要说Spring IOC,之前的文章你还没有说够嘛?


谁让Spring中关于IOC这部分的内容这么多呢,前面的文章还没有说的很细。所以只能继续慢慢往下唠叨了。废话不多说,我们来继续IOC。


BeanDefinition是用来描述Spring中的Bean,是包装Bean的数据结构。其源码如下所示:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
  //标准单例作用域的作用域标识符:“singleton”,对于扩展的bean工厂可能支持更多的作用域
  String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
  //标准原型作用域的范围标识符:“prototype”
  String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
  //表示BeanDefinition是应用程序主要部分的角色提示,通常对应于用户定义的bean
  int ROLE_APPLICATION = 0;
  //表示BeanDefinition是某些大型配置的支持部分的角色提示,通常是一个外部ComponentDefinition。
  //当查看某个特定的ComponentDefinition时,认为bean非常重要,
  //以便在查看应用程序的整体配置时能够意识到这一点
  int ROLE_SUPPORT = 1;
  //角色提示表明一个BeanDefinition是提供一个完全背景的角色,并且与最终用户没有关系。
  //这个提示用于注册完全是ComponentDefinition内部工作的一部分的bean
  int ROLE_INFRASTRUCTURE = 2;
  //1、当前Bean父类名称
  //如果父类存在,设置这个bean定义的父定义的名称
  void setParentName(@Nullable String parentName);
  //如果父类存在,则返回当前Bean的父类的名称
  @Nullable
  String getParentName();
  //2、当前Bean的className
  //指定此bean定义的bean类名称。
  //类名称可以在bean factory后期处理中修改,通常用它的解析变体替换原来的类名称
  void setBeanClassName(@Nullable String beanClassName);
  //返回此bean定义的当前bean类名称
  //需要注意的是,这不一定是在运行时使用的实际类名,以防子类定义覆盖/继承其父类的类名
  //此外,这可能只是调用工厂方法的类,或者它 在调用方法的工厂bean引用的情况下甚至可能是空的
  //因此,不要认为这是在运行时定义的bean类型,而只是将其用于在单独的bean定义级别进行解析
  @Nullable
  String getBeanClassName();
  //3、bean作用域
  //覆盖此bean的目标范围,指定一个新的范围名称
  void setScope(@Nullable String scope);
  //返回此bean的当前目标作用域的名称,如果没有确定,返回null
  @Nullable
  String getScope();
  //懒加载
  //设置这个bean是否应该被延迟初始化。如果{false},那么这个bean将在启动时由bean工厂实例化,
  //这些工厂执行单例的立即初始化。
  //懒加载 <bean lazy-init="true/false">
  void setLazyInit(boolean lazyInit);
  //返回这个bean是否应该被延迟初始化,即不是在启动时立即实例化。只适用于单例bean。
  boolean isLazyInit();
  //5.依赖关系设置
  //设置这个bean依赖被初始化的bean的名字。 bean工厂将保证这些bean首先被初始化。
  //<bean depends-on="">
  void setDependsOn(@Nullable String... dependsOn);
  //返回这个bean依赖的bean名称
  @Nullable
  String[] getDependsOn();
  //6.是否是自动转配设置
  //设置这个bean是否是获得自动装配到其他bean的候选人。
  //需要注意是,此标志旨在仅影响基于类型的自动装配。
  //它不会影响按名称的显式引用,即使指定的bean没有标记为autowire候选,也可以解决这个问题。
  //因此,如果名称匹配,通过名称的自动装配将注入一个bean。
  void setAutowireCandidate(boolean autowireCandidate);
  //返回这个bean是否是自动装配到其他bean的候选者。就是是否在其他类中使用autowired来注入当前Bean的
  //是否为被自动装配 <bean autowire-candidate="true/false">
  boolean isAutowireCandidate();
  //7.主候选Bean
  //是否为主候选bean    使用注解:@Primary
  void setPrimary(boolean primary);
  //返回这个bean是否是主要的autowire候选者
  boolean isPrimary();
  //8.定义创建该Bean对象的工厂类
  //指定要使用的工厂bean(如果有的话), 这是调用指定的工厂方法的bean的名称
  void setFactoryBeanName(@Nullable String factoryBeanName);
  //如果有返回工厂bean的名字
  @Nullable
  String getFactoryBeanName();
  //9.创建该Bean对象的工厂方法
  //如果有,指定工厂方法。这个方法先将通过构造函数参数被调用,或者如果参数,将调用该方法的无参数构造
  void setFactoryMethodName(@Nullable String factoryMethodName);
  //如果存在,返回工厂方法名
  @Nullable
  String getFactoryMethodName();
  //10.返回此bean的构造函数参数值
  //返回此bean的构造函数参数值
  ConstructorArgumentValues getConstructorArgumentValues();
  default boolean hasConstructorArgumentValues() {
    return !getConstructorArgumentValues().isEmpty();
  }
  //11.获取属性
  MutablePropertyValues getPropertyValues();
  default boolean hasPropertyValues() {
    return !getPropertyValues().isEmpty();
  }
  //12.设置初始方法
  void setInitMethodName(@Nullable String initMethodName);
  @Nullable
  String getInitMethodName();
  void setDestroyMethodName(@Nullable String destroyMethodName);
  @Nullable
  String getDestroyMethodName();
  void setRole(int role);
  //13.当前Bean的角色
  //获取这个bean的角色
  int getRole();
  void setDescription(@Nullable String description);
  //14.可读描述
  //返回对bean定义的可读描述
  @Nullable
  String getDescription();
  //返回该bean定义来自的资源的描述
  @Nullable
  String getResourceDescription();
  //返回原始的BeanDefinition;如果没有,则返回null。允许检索装饰的bean定义
  @Nullable
  BeanDefinition getOriginatingBeanDefinition();
  //15.当前Bean的基本特性
  //是否是单例的
  boolean isSingleton();
  //是否是多例的
  boolean isPrototype();
  //是否是抽象类
  boolean isAbstract();
}

从上面的属性和方法分析可以看出,BeanDefinition对于一个Bean的描述做了比较完整的一套约束。这为后续的实现类提供了最基本的职责和属性。BeanDefinition只是一个接口,它的具体实现如下所示:

image.png

二、BeanDefinitionRegistry

BeanDefinitionRegistry 继承了 AliasRegistry 接口,其核心子类有三个:SimpleBeanDefinitionRegistry、DefaultListableBeanFactory以及GenericApplicationContext,类机构图如下所示:

image.png

AliasRegistry 作为 BeanDefinitionRegistry 的顶层接口,它的作用主要为别名管理的通用型接口, AliasRegistry 定义了一些别名管理的方法。

public interface AliasRegistry {
  void registerAlias(String name, String alias);
  void removeAlias(String alias);
  boolean isAlias(String name);
  String[] getAliases(String name);
}

BeanDefinitionRegistry 接口在实现AliasRegistry之外还定义了关于 BeanDefinition 注册、注销、查询等一系列的操作。

public interface BeanDefinitionRegistry extends AliasRegistry {
  // 向注册表中注册一个新的 BeanDefinition 实例
  void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException;
   // 移除注册表中已注册的 BeanDefinition 实例
  void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
   // 从注册中取得指定的 BeanDefinition 实例
  BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
   // 判断 BeanDefinition 实例是否在注册表中(是否注册)
  boolean containsBeanDefinition(String beanName);
  // 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
  String[] getBeanDefinitionNames();
  // 返回注册表中 BeanDefinition 实例的数量
  int getBeanDefinitionCount();
  // beanName(标识)是否被占用
  boolean isBeanNameInUse(String beanName);
}

我们可以看下BeanDefinitionRegistry的类实现结构如下所示:

image.png

这里关注下实现类GenericApplicationContext,其中比较重要的方法为registerBeanDefinition,它完成了BeanDefinition的注册 :

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
  private final DefaultListableBeanFactory beanFactory;
  ...
  @Override
  public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
    this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
  }
  ...
}

注册过程实际是通过DefaultListableBeanFactoryregisterBeanDefinition来完成注册动作:

@Override
  public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
        ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
            "Validation of bean definition failed", ex);
      }
    }
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
        throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
        // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
        if (logger.isInfoEnabled()) {
          logger.info("Overriding user-defined bean definition for bean '" + beanName +
              "' with a framework-generated bean definition: replacing [" +
              existingDefinition + "] with [" + beanDefinition + "]");
        }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
        if (logger.isDebugEnabled()) {
          logger.debug("Overriding bean definition for bean '" + beanName +
              "' with a different definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      else {
        if (logger.isTraceEnabled()) {
          logger.trace("Overriding bean definition for bean '" + beanName +
              "' with an equivalent definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
      if (hasBeanCreationStarted()) {
        // Cannot modify startup-time collection elements anymore (for stable iteration)
        synchronized (this.beanDefinitionMap) {
          this.beanDefinitionMap.put(beanName, beanDefinition);
          List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
          updatedDefinitions.addAll(this.beanDefinitionNames);
          updatedDefinitions.add(beanName);
          this.beanDefinitionNames = updatedDefinitions;
          if (this.manualSingletonNames.contains(beanName)) {
            Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
            updatedSingletons.remove(beanName);
            this.manualSingletonNames = updatedSingletons;
          }
        }
      }
      else {
        // Still in startup registration phase
        this.beanDefinitionMap.put(beanName, beanDefinition);
        this.beanDefinitionNames.add(beanName);
        this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
    }
    if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
    }
  }

其实上面这么多代码最重要的就是:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
this.beanDefinitionMap.put(beanName, beanDefinition);

三、总结

本文主要介绍了BeanDefinition以及BeanDefinition的注册,BeanDefinition是Spring处理Bean的统一的数据结构,BeanDefinitionRegistry的实现类对BeanDefinition完成了注册操作,注册最终结果保存在beanDefinitionMap这个ConcurrentHashMap中。今天的内容就到这里了,我们下次再会了哦。


相关文章
|
1月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
36 0
|
4天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
2天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
11天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
56 14
|
24天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
44 2
|
1月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
1月前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
34 0
|
1月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
67 9
|
Java API Spring
Spring学习路径
Spring作为一个优秀的开源企业级框架有着一下特点 开源框架 简化企业级应用开发的流程 Spring是一个JavaSE/EE的一站式框架 优点在于 方便解耦 AOP的编程支持 声明式事务的支持 可以引入jUnit4,方便程序测试 对优秀开源框架的支持,方便集成 降低JavaEE API的使用难度.
2518 0
|
2月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
245 2