From 676b2235ea886aed07f69b45d5a386c86f3c7a8d Mon Sep 17 00:00:00 2001 From: xuchengsheng Date: Sat, 4 Nov 2023 11:50:41 +0800 Subject: [PATCH] =?UTF-8?q?BeanDefinitionRegistry=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring-beans/pom.xml | 1 + .../README.md | 265 ++++++++++++++++++ .../pom.xml | 14 + .../spring/BeanDefinitionRegistryDemo.java | 50 ++++ .../main/java/com/xcs/spring/bean/MyBean.java | 9 + 5 files changed, 339 insertions(+) create mode 100644 spring-beans/spring-bean-beanDefinitionRegistry/README.md create mode 100644 spring-beans/spring-bean-beanDefinitionRegistry/pom.xml create mode 100644 spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/BeanDefinitionRegistryDemo.java create mode 100644 spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/bean/MyBean.java diff --git a/spring-beans/pom.xml b/spring-beans/pom.xml index 4b556aa..cb522a6 100644 --- a/spring-beans/pom.xml +++ b/spring-beans/pom.xml @@ -15,6 +15,7 @@ spring-bean-beanDefinition spring-bean-beanDefinitionHolder + spring-bean-beanDefinitionRegistry \ No newline at end of file diff --git a/spring-beans/spring-bean-beanDefinitionRegistry/README.md b/spring-beans/spring-bean-beanDefinitionRegistry/README.md new file mode 100644 index 0000000..d856c81 --- /dev/null +++ b/spring-beans/spring-bean-beanDefinitionRegistry/README.md @@ -0,0 +1,265 @@ +## BeanDefinitionRegistry + +- [BeanDefinitionRegistry](#beandefinitionregistry) + - [一、知识储备](#一知识储备) + - [二、基本描述](#二基本描述) + - [三、主要功能](#三主要功能) + - [四、接口源码](#四接口源码) + - [五、主要实现](#五主要实现) + - [六、最佳实践](#六最佳实践) + - [七、与其他组件的关系](#七与其他组件的关系) + - [八、常见问题](#八常见问题) + +### 一、知识储备 + +1. **Bean定义:** + - 理解什么是Bean定义,包括Bean的名称、类名、作用域、依赖关系等。 + - 了解如何使用XML配置、注解或Java配置来定义Bean。 + - 掌握Bean定义中的属性设置、构造函数注入、属性注入等相关概念。 + +### 二、基本描述 + +`BeanDefinitionRegistry`接口是Spring框架中的一个关键接口之一,用于管理和注册Bean定义(Bean definitions)。Bean定义是描述Spring容器中的对象(Bean)的元数据,包括Bean的类名、依赖关系、作用域等信息。 + +### 三、主要功能 + +1. **注册Bean定义** + + 通过 `BeanDefinitionRegistry` 接口,我们可以向Spring容器注册Bean定义。这意味着我们可以将Bean的元数据信息(如类名、作用域、属性等)添加到容器中,以便容器能够根据这些定义实例化和管理Bean对象。 +2. **移除Bean定义** + + 我们可以使用接口提供的方法来移除不再需要的Bean定义。这可以有助于释放资源和减轻容器的负担。通常,这是在运行时不再需要某些Bean定义时使用的功能。 +3. **检查Bean定义是否存在** + + 我们可以使用接口提供的方法来检查容器中是否存在特定名称的Bean定义。这可以帮助我们避免重复注册相同名称的Bean。 +4. **获取Bean定义信息** + + 通过接口,我们可以获取已注册的Bean定义的详细信息,包括Bean的类名、作用域、属性值等。这对于在运行时查看或修改Bean定义很有用。 +5. **批量操作** + + 除了单个Bean定义的操作,`BeanDefinitionRegistry` 还支持批量注册和移除操作。这对于在一次操作中注册多个Bean定义非常有用,以减少重复的操作。 +6. **层次性注册** + + Spring容器可以是层次性的,其中可以包含多个容器层次结构。`BeanDefinitionRegistry` 接口支持在这些容器层次结构中注册Bean定义。这对于分模块的应用程序非常有用。 +7. **自定义扩展** + + Spring框架允许通过自定义实现 `BeanDefinitionRegistry` 接口来创建自定义的Bean定义注册器,以满足特定的需求。这使得Spring框架具有高度的可扩展性。 + +### 四、接口源码 + +`BeanDefinitionRegistry` 接口,用于管理和注册Bean定义。它允许我们注册、移除、检索Bean定义以及执行其他与Bean定义相关的操作。这个接口用于实现Spring的IOC容器,允许我们在应用程序中注册并管理Bean定义,使其能够进行依赖注入。 + +```java +/** + * 用于持有Bean定义(例如RootBeanDefinition和ChildBeanDefinition实例)的注册表的接口。 + * 通常由与AbstractBeanDefinition层次结构内部一起工作的Bean工厂实现。 + * + * 这是Spring的bean工厂包中唯一封装注册bean定义的接口。 + * 标准的BeanFactory接口只覆盖对完全配置的工厂实例的访问。 + * + * Spring的Bean定义读取器希望在这个接口的实现上工作。 + * Spring核心中已知的实现者包括DefaultListableBeanFactory和GenericApplicationContext。 + * + * @author Juergen Hoeller + * @since 26.11.2003 + * @see org.springframework.beans.factory.config.BeanDefinition + * @see AbstractBeanDefinition + * @see RootBeanDefinition + * @see ChildBeanDefinition + * @see DefaultListableBeanFactory + * @see org.springframework.context.support.GenericApplicationContext + * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader + * @see PropertiesBeanDefinitionReader + */ +public interface BeanDefinitionRegistry extends AliasRegistry { + + /** + * 向此注册表注册一个新的Bean定义。 + * 必须支持RootBeanDefinition和ChildBeanDefinition。 + * + * @param beanName 要注册的Bean实例的名称 + * @param beanDefinition 要注册的Bean实例的定义 + * @throws BeanDefinitionStoreException 如果BeanDefinition无效 + * @throws BeanDefinitionOverrideException 如果已经存在指定名称的BeanDefinition并且不允许覆盖 + * @see GenericBeanDefinition + * @see RootBeanDefinition + * @see ChildBeanDefinition + */ + void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) + throws BeanDefinitionStoreException; + + /** + * 移除给定名称的BeanDefinition。 + * + * @param beanName 要注册的Bean实例的名称 + * @throws NoSuchBeanDefinitionException 如果没有这样的Bean定义 + */ + void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; + + /** + * 返回给定Bean名称的BeanDefinition。 + * + * @param beanName 要查找定义的Bean名称 + * @return 给定名称的BeanDefinition(永远不为{@code null}) + * @throws NoSuchBeanDefinitionException 如果没有这样的Bean定义 + */ + BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; + + /** + * 检查此注册表是否包含给定名称的Bean定义。 + * + * @param beanName 要查找的Bean的名称 + * @return 如果此注册表包含给定名称的Bean定义,则返回true + */ + boolean containsBeanDefinition(String beanName); + + /** + * 返回此注册表中定义的所有Bean的名称。 + * + * @return 此注册表中定义的所有Bean的名称数组,如果没有定义则返回空数组 + */ + String[] getBeanDefinitionNames(); + + /** + * 返回注册表中定义的Bean数量。 + * + * @return 注册表中定义的Bean数量 + */ + int getBeanDefinitionCount(); + + /** + * 确定给定的Bean名称是否已在此注册表中使用,即是否已在此名称下注册了本地Bean或别名。 + * + * @param beanName 要检查的名称 + * @return 给定的Bean名称是否已经在使用 + */ + boolean isBeanNameInUse(String beanName); + +} +``` + +### 五、主要实现 + +1. **`DefaultListableBeanFactory`** + + 这是Spring框架中最常用的`BeanDefinitionRegistry` 接口的实现之一。它是Spring的核心容器,负责管理Bean定义,实例化Bean对象以及提供依赖注入功能。通常,我们可以在XML配置文件中配置`DefaultListableBeanFactory`来定义和注册Bean。 +2. **`GenericApplicationContext`** + + `GenericApplicationContext` 是Spring的应用上下文的实现,它实现了 `BeanDefinitionRegistry` 接口。这个上下文是一个通用的应用程序上下文,可以用于在程序中注册和管理Bean定义。 +3. **`SimpleBeanDefinitionRegistry`** + + `SimpleBeanDefinitionRegistry`提供了基本的`BeanDefinition`注册和管理功能,但它相对较简单,不支持高级特性,如XML配置解析等。它通常用于快速原型开发、单元测试和一些较为简单的应用程序中,以减少配置和复杂性。 + +~~~mermaid +classDiagram + direction BT + + class AliasRegistry { + <> + } + + class BeanDefinitionRegistry { + <> + } + + class DefaultListableBeanFactory { + } + + class GenericApplicationContext { + } + + class SimpleBeanDefinitionRegistry { + } + + BeanDefinitionRegistry ..|> AliasRegistry + DefaultListableBeanFactory --|> BeanDefinitionRegistry + GenericApplicationContext --|> BeanDefinitionRegistry + SimpleBeanDefinitionRegistry --|> BeanDefinitionRegistry + +~~~ + +### 六、最佳实践 + +我们使用Spring的`DefaultListableBeanFactory`和`BeanDefinitionRegistry`接口来注册、管理和操作Bean定义的过程,包括创建Bean定义、注册到容器、获取、检查是否存在、获取所有定义的名称和数量、检查名称是否已使用,以及移除Bean定义。这展示了Spring的IOC容器的核心功能,允许应用程序在运行时动态配置和管理Bean。 + +```java +public class BeanDefinitionRegistryDemo { + + public static void main(String[] args) { + // 创建一个BeanFactory,它是BeanDefinitionRegistry + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + + // 创建一个Bean定义 + GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); + beanDefinition.setBeanClass(MyBean.class); + + // 注册Bean定义到BeanFactory + beanFactory.registerBeanDefinition("myBean", beanDefinition); + + // 获取BeanDefinition + BeanDefinition retrievedBeanDefinition = beanFactory.getBeanDefinition("myBean"); + System.out.println("Bean定义的类名 = " + retrievedBeanDefinition.getBeanClassName()); + + // 检查Bean定义是否存在 + boolean containsBeanDefinition = beanFactory.containsBeanDefinition("myBean"); + System.out.println("Bean定义是否包含(myBean) = " + containsBeanDefinition); + + // 获取所有Bean定义的名称 + String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); + System.out.println("Bean定义的名称 = " + String.join(", ", beanDefinitionNames)); + + // 获取Bean定义的数量 + int beanDefinitionCount = beanFactory.getBeanDefinitionCount(); + System.out.println("Bean定义的数量 = " + beanDefinitionCount); + + // 检查Bean名称是否已被使用 + boolean isBeanNameInUse = beanFactory.isBeanNameInUse("myBean"); + System.out.println("Bean名称(myBean)是否被使用 = " + isBeanNameInUse); + + // 移除Bean定义 + beanFactory.removeBeanDefinition("myBean"); + System.out.println("Bean定义已被移除(myBean)"); + } +} +``` + +`MyBean` 的Java类,代表了一个简单的Java Bean。 + +```java +public class MyBean { + +} +``` + +运行结果发现,我们的各种操作已成功执行,包括注册、查询、操作和移除Bean定义。这展示了Spring的IoC容器的核心功能,使我们可以在运行时动态地管理Bean定义。 + +```java +Bean定义的类名 = com.xcs.spring.bean.MyBean +Bean定义是否包含(myBean) = true +Bean定义的名称 = myBean +Bean定义的数量 = 1 +Bean名称(myBean)是否被使用 = true +Bean定义已被移除(myBean) +``` + +### 七、与其他组件的关系 + +1. **`DefaultListableBeanFactory`** + + `BeanDefinitionRegistry` 是`DefaultListableBeanFactory`的一个主要实现,它负责注册和管理Bean定义(`BeanDefinition`)。 `BeanFactory`是Spring的IOC容器,用于实例化和管理Bean对象。 `DefaultListableBeanFactory`可以通过 `BeanDefinitionRegistry` 来注册和获取Bean定义,然后使用这些定义来创建Bean实例。 +2. **`GenericApplicationContext`** + + `GenericApplicationContext` 是`DefaultListableBeanFactory`的更高级别扩展,它不仅实现了 `DefaultListableBeanFactory` 的功能,还提供了应用程序级别的服务,如国际化、事件发布、资源加载等。 `DefaultListableBeanFactory` 通常使用 `BeanDefinitionRegistry` 来注册和管理Bean定义,以便在应用程序上下文中配置和管理Bean。 +3. **`BeanDefinition`** + + `BeanDefinitionRegistry` 主要与Bean定义(`BeanDefinition`)相关联。它用于注册、查询和管理Bean定义,包括Bean的类名、作用域、依赖关系等元数据信息。 `BeanFactory` 和 `ApplicationContext` 使用这些Bean定义来创建和管理Bean实例。 +4. **`BeanPostProcessor`** + + `BeanPostProcessor` 是一个拦截Bean实例化的接口,`DefaultListableBeanFactory`和 `GenericApplicationContext` 中都可以使用。 `BeanDefinitionRegistry` 可以与 `BeanPostProcessor` 结合使用,以在Bean的实例化前后执行定制的处理逻辑。这允许我们在Bean创建过程中干预并定制Bean的初始化和销毁过程。 + +### 八、常见问题 + +1. **什么是 `BeanDefinitionRegistry`?** + - `BeanDefinitionRegistry` 是Spring框架中的一个接口,它用于注册和管理Bean定义。它是IOC容器的核心组成部分,用于将应用程序中的Bean定义注册到容器中,以便后续实例化和管理。 +2. **`BeanDefinitionRegistry` 与 `DefaultListableBeanFactory` 之间的关系是什么?** + - `DefaultListableBeanFactory` 是Spring的IOC容器,而 `BeanDefinitionRegistry` 是 `DefaultListableBeanFactory` 的一个具体实现。它允许 `DefaultListableBeanFactory` 在内部管理和访问Bean定义。 `DefaultListableBeanFactory` 实际上是一个包含了 `BeanDefinitionRegistry` 功能的IOC容器。 +3. **`BeanDefinition` 和 `BeanDefinitionRegistry` 之间的关系是什么?** + - `BeanDefinition` 是Bean定义的元数据,它描述了如何创建和配置Bean。 `BeanDefinitionRegistry` 用于注册和管理这些 `BeanDefinition`。 `BeanDefinitionRegistry` 允许我们注册Bean定义并在容器中实例化这些Bean。 +4. **如何使用 `BeanDefinitionRegistry` 注册Bean定义?** + - 我们可以创建一个实现了 `BeanDefinitionRegistry` 接口的容器(如 `DefaultListableBeanFactory` 或 `GenericApplicationContext`),然后使用其 `registerBeanDefinition` 方法来注册Bean定义。通常,我们需要提供Bean的名称和相应的 `BeanDefinition`。 +5. **可以注册多个相同名称的Bean吗?** + - 默认情况下,我们不能注册多个相同名称的Bean。如果尝试注册相同名称的Bean,通常会抛出 `BeanDefinitionOverrideException` 异常。但有些情况下,我们可以允许覆盖现有的Bean定义。 +6. **如何检查是否存在特定名称的Bean定义?** + - 我们可以使用 `containsBeanDefinition` 方法来检查是否存在特定名称的Bean定义。这个方法将返回一个布尔值,指示是否存在该Bean定义。 +7. **如何获取已注册的Bean定义的名称和数量?** + - 使用 `getBeanDefinitionNames` 方法可以获取所有已注册的Bean定义的名称数组,而使用 `getBeanDefinitionCount` 方法可以获取已注册的Bean定义的数量。 +8. **如何移除已注册的Bean定义?** + - 我们可以使用 `removeBeanDefinition` 方法来移除已注册的Bean定义。这将从容器中删除该Bean定义,使其不再可用。 +9. **`BeanDefinitionRegistry`与`BeanPostProcessor` 之间有什么关系?** + - `BeanPostProcessor` 是一个接口,用于在Bean实例化和初始化过程中进行处理。 `BeanDefinitionRegistry` 可以与 `BeanPostProcessor` 结合使用,以在Bean定义的创建和初始化过程中执行自定义逻辑。这允许我们在Bean创建时进行定制操作。 \ No newline at end of file diff --git a/spring-beans/spring-bean-beanDefinitionRegistry/pom.xml b/spring-beans/spring-bean-beanDefinitionRegistry/pom.xml new file mode 100644 index 0000000..7e2e868 --- /dev/null +++ b/spring-beans/spring-bean-beanDefinitionRegistry/pom.xml @@ -0,0 +1,14 @@ + + + + spring-beans + com.xcs.spring + 0.0.1-SNAPSHOT + + + 4.0.0 + spring-bean-beanDefinitionRegistry + + \ No newline at end of file diff --git a/spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/BeanDefinitionRegistryDemo.java b/spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/BeanDefinitionRegistryDemo.java new file mode 100644 index 0000000..b348f16 --- /dev/null +++ b/spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/BeanDefinitionRegistryDemo.java @@ -0,0 +1,50 @@ +package com.xcs.spring; + +import com.xcs.spring.bean.MyBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.GenericBeanDefinition; + +/** + * @author xcs + * @date 2023年11月04日 11时28分 + **/ +public class BeanDefinitionRegistryDemo { + + public static void main(String[] args) { + // 创建一个BeanFactory,它是BeanDefinitionRegistry + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + + // 创建一个Bean定义 + GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); + beanDefinition.setBeanClass(MyBean.class); + + // 注册Bean定义到BeanFactory + beanFactory.registerBeanDefinition("myBean", beanDefinition); + + // 获取BeanDefinition + BeanDefinition retrievedBeanDefinition = beanFactory.getBeanDefinition("myBean"); + System.out.println("Bean定义的类名 = " + retrievedBeanDefinition.getBeanClassName()); + + // 检查Bean定义是否存在 + boolean containsBeanDefinition = beanFactory.containsBeanDefinition("myBean"); + System.out.println("Bean定义是否包含(myBean) = " + containsBeanDefinition); + + // 获取所有Bean定义的名称 + String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); + System.out.println("Bean定义的名称 = " + String.join(", ", beanDefinitionNames)); + + // 获取Bean定义的数量 + int beanDefinitionCount = beanFactory.getBeanDefinitionCount(); + System.out.println("Bean定义的数量 = " + beanDefinitionCount); + + // 检查Bean名称是否已被使用 + boolean isBeanNameInUse = beanFactory.isBeanNameInUse("myBean"); + System.out.println("Bean名称(myBean)是否被使用 = " + isBeanNameInUse); + + // 移除Bean定义 + beanFactory.removeBeanDefinition("myBean"); + System.out.println("Bean定义已被移除(myBean)"); + } +} diff --git a/spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/bean/MyBean.java b/spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/bean/MyBean.java new file mode 100644 index 0000000..ad982bf --- /dev/null +++ b/spring-beans/spring-bean-beanDefinitionRegistry/src/main/java/com/xcs/spring/bean/MyBean.java @@ -0,0 +1,9 @@ +package com.xcs.spring.bean; + +/** + * @author xcs + * @date 2023年11月01日 15时41分 + **/ +public class MyBean { + +}