BeanDefinitionHolder源码分析
parent
388dc8bdb7
commit
bcdcdcca61
|
@ -60,24 +60,26 @@
|
|||
|
||||
## 🌱Spring 源码阅读系列
|
||||
|
||||
1. **IOC 容器**
|
||||
1. **IOC容器**
|
||||
- 资源加载与访问
|
||||
- Resource
|
||||
- ResourceLoader
|
||||
- 元数据
|
||||
- MetadataReader
|
||||
- AnnotationMetadata
|
||||
- Bean的定义与注册
|
||||
- Bean定义与注册
|
||||
- BeanDefinition
|
||||
- BeanDefinitionHolder
|
||||
- BeanDefinitionRegistry
|
||||
|
||||
- Bean定义加载与扫描
|
||||
- XmlBeanDefinitionReader
|
||||
- PropertiesBeanDefinitionReader
|
||||
- AnnotatedBeanDefinitionReader
|
||||
- ClassPathBeanDefinitionScanner
|
||||
- Bean定义导入与组合
|
||||
- ImportBeanDefinitionRegistrar
|
||||
- BeanDefinitionImportSelector
|
||||
- ImportSelector
|
||||
- DeferredImportSelector
|
||||
- Bean的过滤
|
||||
- TypeFilter
|
||||
- ConditionEvaluator
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>spring-bean-beanDefinition</module>
|
||||
<module>spring-bean-beanDefinitionHolder</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,216 @@
|
|||
## BeanDefinitionHolder
|
||||
|
||||
- [BeanDefinitionHolder](#beandefinitionholder)
|
||||
- [一、知识储备](#一知识储备)
|
||||
- [二、基本描述](#二基本描述)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、接口源码](#四接口源码)
|
||||
- [五、主要实现](#五主要实现)
|
||||
- [六、最佳实践](#六最佳实践)
|
||||
- [七、与其他组件的关系](#七与其他组件的关系)
|
||||
- [八、常见问题](#八常见问题)
|
||||
|
||||
|
||||
### 一、知识储备
|
||||
|
||||
1. **Spring Framework 基础知识**
|
||||
+ 我们需要熟悉 Spring Framework 的基本概念,包括什么是 Bean,什么是 `BeanDefinition`,以及 Spring 容器是如何管理和实例化 Bean 的。
|
||||
2. **`BeanDefinition`的理解**
|
||||
+ 我们需要了解什么是 `BeanDefinition`,它包含了哪些信息,例如 Bean 的类名、作用域、属性、初始化方法、销毁方法等。这是理解 `BeanDefinitionHolder` 的基础。
|
||||
3. **Spring IOC 容器**
|
||||
+ 我们需要了解 Spring 的 IOC(Inversion 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名称的唯一性。
|
|
@ -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-beanDefinitionHolder</artifactId>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,39 @@
|
|||
package com.xcs.spring;
|
||||
|
||||
import com.xcs.spring.bean.MyBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author xcs
|
||||
* @date 2023年11月03日 17时20分
|
||||
**/
|
||||
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"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.xcs.spring.bean;
|
||||
|
||||
/**
|
||||
* @author xcs
|
||||
* @date 2023年11月01日 15时41分
|
||||
**/
|
||||
public class MyBean {
|
||||
|
||||
}
|
Loading…
Reference in New Issue