《Spring Boot 3:高级与架构设计》第 1 章 BeanDefinitionRegistry 个人理解 3
1 什么是 BeanDefinitionRegistry
BeanDefinition 是 Bean 的元信息,即 Bean 的定义信息。
BeanDefinitionRegistry 是 BeanDefinition 的注册表,负责保存和维护 BeanDefinition 的信息。
2 BeanDefinitionRegistry 中存放了所有 BeanDefinition 的信息
BeanDefinitionRegistry 是一个接口,DefaultListableBeanFactory 是实现类。

Spring Framework 底层对于 BeanDefinition 的注册表的设计,本质上就是一个 Map,如代码所示。

3 BeanDefinitionRegistry 可以维护 BeanDefinition 的信息
BeanDefinitionRegistry 中有 3 个方法,刚好对应了 BeanDefinition 的增、删、查,如代码所示。

4 BeanDefinitionRegistry 的作用
BeanDefinitionRegistry 可以向 IOC 容器中注入 BeanDefinition,IOC 容器再将 BeanDefinition 转为了 Bean。
4.4.6 节,使用 BeanDefinitionRegistry 的案例
5 DefaultListableBeanFactory 是主要实现类
DefaultListableBeanFactory 是 BeanDefinitionRegistry 的主要实现类,
GenericApplicationContext 也是 BeanDefinition 的实现类,但是内部依赖了 DefaultListableBeanFactory 进行 BeanDefinition 的管理。

6 使用 BeanDefinitionRegistry 注册 BeanDefinition
4.4.6 节,使用 BeanDefinitionRegistry 的案例
7 实现 BeanDefinitionRegistry 移除 BeanDefinition
移除 BeanDefinition 的操作会在 Bean 的实例化之前进行,目的是阻止 IOC 容器创建对应的 Bean。
7.1 新建一个 Person 类

java
package com.yangjunbo.spring.definition.examplec;
/**
* ClassName: Person
* Package: com.yangjunbo.spring.definition.examplec
* Description:
*
* @Author 杨钧博
* @Create 2026/9/7 22:35
* @Version 1.0
*/
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
7.2 编写配置文件
接下来要注册两个 Person 对象,分别是一个成年人和一个儿童。
由 1.3.3 节最后总结的 BeanDefinition 注册方式与实现类型可知,如果此处使用注解配置类的方式注册 Bean(借助 @Bean),生成的 BeanDefinition 将无法获取 beanClassName,也无法获取 PropertyValues,故此处选用 XML 配置文件的方式注册 Bean,如代码所示。

xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="chengnianren" class="com.yangjunbo.spring.definition.examplec.bean.Person">
<property name="name" value="chengnianren"/>
<property name="age" value="18"/>
</bean>
<bean id="ertong" class="com.yangjunbo.spring.definition.examplec.bean.Person">
<property name="name" value="ertong"/>
<property name="age" value="8"/>
</bean>
</beans>
7.3 编写移除 BeanDefinition 的组件
移除 BeanDefinition 时需要用到后置处理器组件 BeanFactoryPostProcessor,这个组件可以在 XML 配置文件或注解配置类加载到 IOC 容器后修改 IOC 容器中的 BeanDefinition。
为此,可以编写一个 RemoveBeanDefinitionPostProcessor,实现 BeanFactoryPostProcessor 接口,并重写必要的 postProcessBeanFactory方法。
注意该方法的入参是一个 ConfigurableListableBeanFactory,毫无疑问,它的唯一实现是 DefaultListableBeanFactory。

DefaultListableBeanFactory 本身又实现了 BeanDefinitionRegistry 接口。

所以相当于可以直接将 ConfigurableListableBeanFactory 强转为 BeanDefinitionRegistry 类型。

得到 BeanDefinitionRegistry 后就可以假定一个移除规则:小于 18 岁的 Person 会被移除。编写方式如代码所示。

java
package com.yangjunbo.spring.definition.examplec.config;
import com.yangjunbo.spring.definition.examplec.bean.Person;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.stereotype.Component;
@Component
public class RemoveBeanDefinitionPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 获取IOC容器中的所有BeanDefinition
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
// 判断BeanDefinition对应的Bean是否为Person类型
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
if (Person.class.getName().equals(beanDefinition.getBeanClassName())) {
// 判断Person的年龄是否大于等于18,小于18的会被移除
TypedStringValue age = (TypedStringValue) beanDefinition.getPropertyValues().get("age");
if (Integer.parseInt(age.getValue()) < 18) {
// 移除BeanDefinition
registry.removeBeanDefinition(beanDefinitionName);
}
}
}
}
}

xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="chengnianren" class="com.yangjunbo.spring.definition.examplec.bean.Person">
<property name="name" value="chengnianren"/>
<property name="age" value="18"/>
</bean>
<bean id="ertong" class="com.yangjunbo.spring.definition.examplec.bean.Person">
<property name="name" value="ertong"/>
<property name="age" value="8"/>
</bean>
<!-- 注意此处要开启组件扫描 -->
<context:component-scan base-package="com.yangjunbo.spring.definition.examplec.config"/>
</beans>
7.4 测试
使用 XML 配置文件驱动 IOC 容器,随后从 IOC 容器中尝试获取 chengnianren 和 ertong,如代码所示。运行 main 方法之后可以发现可以正常获取 chengnianren,但是获取 ertong 时会打印 NoSuchBeanDefinitionException,这说明 ertong 对应的 BeanDefinition 已经被移除,无法创建对应的 Bean。

java
package com.yangjunbo.spring.definition.examplec;
import com.yangjunbo.spring.definition.examplec.bean.Person;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: ExampleCApplication
* Package: com.yangjunbo.spring.definition.examplec
* Description:
*
* @Author 杨钧博
* @Create 2026/9/7 22:59
* @Version 1.0
*/
public class ExampleCApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("examplec/spring-examplec.xml");
Person dazhuang = (Person) ctx.getBean("chengnianren");
System.out.println(dazhuang);
Person xiaoming = (Person) ctx.getBean("ertong");
System.out.println(xiaoming);
}
}