spring-reading./spring-beans/spring-bean-beanDefinitionH.../README.md

216 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## BeanDefinitionHolder
- [BeanDefinitionHolder](#beandefinitionholder)
- [一、知识储备](#一知识储备)
- [二、基本描述](#二基本描述)
- [三、主要功能](#三主要功能)
- [四、接口源码](#四接口源码)
- [五、主要实现](#五主要实现)
- [六、最佳实践](#六最佳实践)
- [七、与其他组件的关系](#七与其他组件的关系)
- [八、常见问题](#八常见问题)
### 一、知识储备
1. **Spring Framework 基础知识**
+ 我们需要熟悉 Spring Framework 的基本概念,包括什么是 Bean什么是 `BeanDefinition`,以及 Spring 容器是如何管理和实例化 Bean 的。
2. **`BeanDefinition`的理解**
+ 我们需要了解什么是 `BeanDefinition`,它包含了哪些信息,例如 Bean 的类名、作用域、属性、初始化方法、销毁方法等。这是理解 `BeanDefinitionHolder` 的基础。
3. **Spring IOC 容器**
+ 我们需要了解 Spring 的 IOCInversion of Control容器包括如何配置容器、如何加载 `BeanDefinition`,以及如何从容器中获取 Bean 实例。
### 二、基本描述
`BeanDefinitionHolder` 是 Spring Framework 中的一个类,用于持有一个 `BeanDefinition` 对象以及与之相关联的名称。它通常用于内部 Spring 操作,用于管理和操作 `BeanDefinition`
### 三、主要功能
1. **持有 `BeanDefinition` 对象**
+ `BeanDefinitionHolder` 主要用于持有一个 `BeanDefinition` 对象,它包含有关 Bean 的元数据信息,如类名、作用域、属性、初始化方法等。
2. **与名称相关联**
+ `BeanDefinitionHolder` 与一个 Bean 的名称相关联,以便可以轻松地标识和操作特定的 `BeanDefinition`
3. **包装`BeanDefinition`**
+ 它包装了 `BeanDefinition` 以及与之关联的名称,将它们组合在一起,形成一个单元,有助于更好地管理和处理 `BeanDefinition`
4. **提供额外的元数据**
+ 除了 `BeanDefinition` 和名称,`BeanDefinitionHolder` 还可以包含其他元数据,如 `BeanDefinition` 的原始来源(通常是一个 Resource 对象)以及 `BeanDefinition` 的描述信息。
5. **用于注册和管理 `BeanDefinition`**
+ `BeanDefinitionHolder` 可以与 `BeanDefinitionRegistry` 接口一起使用,用于在 Spring 容器中注册、修改和管理 `BeanDefinition`
### 四、接口源码
`BeanDefinitionHolder` 通常在 Spring 内部用于处理 `BeanDefinition` 注册和操作,提供了访问 `BeanDefinition`、Bean 名称和别名的方法。
```java
public class BeanDefinitionHolder implements BeanMetadataElement {
// 封装的 BeanDefinition 对象
private final BeanDefinition beanDefinition;
// Bean 的名称
private final String beanName;
// 别名数组
@Nullable
private final String[] aliases;
/**
* 创建一个新的 BeanDefinitionHolder。
* @param beanDefinition 要包装的 BeanDefinition
* @param beanName Bean 的名称,如在 Bean 定义中指定
*/
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
this(beanDefinition, beanName, null);
}
/**
* 创建一个新的 BeanDefinitionHolder。
* @param beanDefinition 要包装的 BeanDefinition
* @param beanName Bean 的名称,如在 Bean 定义中指定
* @param aliases Bean 的别名,如果没有别名则为 null
*/
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, @Nullable String[] aliases) {
Assert.notNull(beanDefinition, "BeanDefinition 必须不为 null");
Assert.notNull(beanName, "Bean 名称必须不为 null");
this.beanDefinition = beanDefinition;
this.beanName = beanName;
this.aliases = aliases;
}
/**
* 复制构造函数:创建一个新的 BeanDefinitionHolder其内容与给定的 BeanDefinitionHolder 实例相同。
* 注意:封装的 BeanDefinition 引用保持原样;不会进行深层复制。
* @param beanDefinitionHolder 要复制的 BeanDefinitionHolder 实例
*/
public BeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {
Assert.notNull(beanDefinitionHolder, "BeanDefinitionHolder 必须不为 null");
this.beanDefinition = beanDefinitionHolder.getBeanDefinition();
this.beanName = beanDefinitionHolder.getBeanName();
this.aliases = beanDefinitionHolder.getAliases();
}
/**
* 返回封装的 BeanDefinition。
*/
public BeanDefinition getBeanDefinition() {
return this.beanDefinition;
}
/**
* 返回 Bean 的主要名称,如在 Bean 定义中指定。
*/
public String getBeanName() {
return this.beanName;
}
/**
* 返回 Bean 的别名数组,如在 Bean 定义中直接指定。
* @return 别名数组,如果没有别名则为 null
*/
@Nullable
public String[] getAliases() {
return this.aliases;
}
/**
* 公开 Bean 定义的源对象。
* @see BeanDefinition#getSource()
*/
@Override
@Nullable
public Object getSource() {
return this.beanDefinition.getSource();
}
/**
* 确定给定的候选名称是否与存储在该 Bean 定义中的 Bean 名称或别名匹配。
*/
public boolean matchesName(@Nullable String candidateName) {
return (candidateName != null && (candidateName.equals(this.beanName) ||
candidateName.equals(BeanFactoryUtils.transformedBeanName(this.beanName)) ||
ObjectUtils.containsElement(this.aliases, candidateName)));
}
// ... [部分代码省略以简化]
}
```
### 五、主要实现
`BeanDefinitionHolder` 不是一个接口,也不需要其他实现类。它是一个具体的类,用于包装 `BeanDefinition` 对象、Bean 名称和别名,以便更好地管理和操作 `BeanDefinition`
### 六、最佳实践
使用 `BeanDefinitionHolder` 和 Spring IOC 容器,通过创建一个 `BeanDefinition` 对象定义了名为 "`myBean`" 的 Bean然后给它指定了别名 "`myBeanX`" 和 "`myBeanY`",并最终将这个 `BeanDefinition` 注册到容器中。随后,使用容器的 `getBean` 方法来检索这些 Bean验证它们的正确注册和别名的设置。
```java
public class BeanDefinitionHolderDemo {
public static void main(String[] args) {
// 创建一个 DefaultListableBeanFactory它是 BeanDefinitionRegistry 的一个实现
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建一个新的 BeanDefinition 对象
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(MyBean.class);
// Bean名称
String beanName = "myBean";
// 设置别名aliases
String[] aliases = {"myBeanX", "myBeanY"};
// 创建一个 BeanDefinitionHolder将 BeanDefinition 与名称关联起来
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName, aliases);
// 使用 BeanDefinitionReaderUtils 注册 BeanDefinitionHolder
BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, beanFactory);
System.out.println("myBean = " + beanFactory.getBean("myBean"));
System.out.println("myBeanX = " + beanFactory.getBean("myBeanX"));
System.out.println("myBeanY = " + beanFactory.getBean("myBeanY"));
}
}
```
`MyBean` 的Java类代表了一个简单的Java Bean。
```java
public class MyBean {
}
```
运行结果发现我们可以使多个名称都引用同一个Bean定义最终获取相同的Bean实例。
```java
myBean = com.xcs.spring.bean.MyBean@5bcea91b
myBeanX = com.xcs.spring.bean.MyBean@5bcea91b
myBeanY = com.xcs.spring.bean.MyBean@5bcea91b
```
### 七、与其他组件的关系
1. **`BeanDefinitionReaderUtils`**
+ Spring 提供了一个实用工具类 `BeanDefinitionReaderUtils`,用于帮助注册 `BeanDefinition`,它通常与 `BeanDefinitionHolder` 一起使用。`BeanDefinitionReaderUtils.registerBeanDefinition` 方法可用于将 `BeanDefinitionHolder` 注册到 `BeanDefinitionRegistry` 中。
2. **`BeanDefinitionParser` 和自定义解析器**
+ 在 Spring XML 配置文件中,`BeanDefinition` 可以通过自定义的 `BeanDefinitionParser``NamespaceHandler` 解析器来解析并注册到容器中。这些解析器通常使用 `BeanDefinitionHolder` 来包装 `BeanDefinition`,并通过解析器注册到容器中。
3. **组件扫描器**
+ Spring 提供了不同的组件扫描器,如 `ClassPathBeanDefinitionScanner``AnnotatedBeanDefinitionReader`,用于扫描类路径或带有注解的类,并将它们注册为 `BeanDefinition`。这些扫描器通常使用 `BeanDefinitionHolder` 来包装扫描到的 `BeanDefinition`,并注册到容器中。
4. **@Import 和相关机制**
+ 在 Spring 中,`@Import` 注解以及相关的 `ImportBeanDefinitionRegistrar``ImportSelector` 接口用于导入其他配置类的 `BeanDefinition`。在这个过程中,`BeanDefinitionHolder` 可能用于包装被导入的 `BeanDefinition`,并将其注册到容器中。
### 八、常见问题
1. **如何使用`BeanDefinitionHolder`**
- `BeanDefinitionHolder` 通常在Spring内部用于处理`BeanDefinition`的注册和操作,但应用开发人员通常不需要直接与它交互(除非你是一个框架开发人员)。它可以在自定义`BeanDefinition`解析器、组件扫描、@Import导入等Spring配置的过程中被自动使用。
2. **`BeanDefinitionHolder`和`BeanDefinition`之间的关系是什么?**
- `BeanDefinitionHolder` 是一个包装器,它包含一个`BeanDefinition`对象以及相关的名称和别名。它用于将`BeanDefinition`与名称关联起来,以便更好地管理和操作`BeanDefinition`。
3. **如何为`BeanDefinition`设置别名?**
- 别名aliases是通过在`BeanDefinitionHolder`构造函数中传递字符串数组来设置的。在注册`BeanDefinitionHolder`时,别名将与`BeanDefinition`一起注册,从而使不同的名称都引用同一个`BeanDefinition`。
4. **是否可以在运行时更改Bean的别名**
- 通常情况下,一旦`BeanDefinition`注册到容器中,别名是固定的,不能在运行时更改。如果需要更改别名,通常需要重新注册`BeanDefinition`,使用不同的别名。
5. **如何判断两个Bean是否有相同的别名**
- 可以使用`BeanDefinitionHolder`的`matchesName`方法来判断给定的候选名称是否与Bean的名称或别名匹配。这个方法会检查给定的名称是否与Bean名称或别名中的任何一个匹配。
6. **别名的作用是什么?**
- 别名提供了更多的灵活性使您可以使用不同的名称来引用同一个Bean。这对于允许不同的组件、模块或配置使用不同的名称来访问Bean定义非常有用。
7. **如何处理具有相同名称的多个`BeanDefinition`**
- 如果多个`BeanDefinition`具有相同的名称,通常情况下,只有最后一个注册的`BeanDefinition`会生效。这可能会导致Bean覆盖的问题因此在配置时要注意Bean名称的唯一性。