BeanDefinitionRegistry源码分析

master
xuchengsheng 2023-11-04 11:50:41 +08:00
parent bcdcdcca61
commit 676b2235ea
5 changed files with 339 additions and 0 deletions

View File

@ -15,6 +15,7 @@
<modules>
<module>spring-bean-beanDefinition</module>
<module>spring-bean-beanDefinitionHolder</module>
<module>spring-bean-beanDefinitionRegistry</module>
</modules>
</project>

View File

@ -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 {
<<interface>>
}
class BeanDefinitionRegistry {
<<interface>>
}
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创建时进行定制操作。

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-beans</artifactId>
<groupId>com.xcs.spring</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-bean-beanDefinitionRegistry</artifactId>
</project>

View File

@ -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 20231104 1128
**/
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)");
}
}

View File

@ -0,0 +1,9 @@
package com.xcs.spring.bean;
/**
* @author xcs
* @date 20231101 1541
**/
public class MyBean {
}