Spring Boot 深入剖析:BootstrapRegistry 与 BeanDefinitionRegistry 的对比
在 Spring Boot 的启动过程中,BootstrapRegistry
和 BeanDefinitionRegistry
是两个名为“Registry”却扮演着截然不同角色的核心接口。理解它们的差异是深入掌握 Spring Boot 启动机制和进行高级定制开发的关键。
BootstrapRegistry
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);}
当我们查看SpringBoot的启动方法的源码,我们发现run方法的源码本质上是初始化了一个SpringApplication对象随后调用其run方法来执行。我们点击进去这个SpringApplication的构造方法中我们看到
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();}
在SpringApplication这个构造方法初始化了两个类分别是BootstrapRegistryInitializer和ApplicationContextInitializer,这两个接口都是只有一个方法initialize,他们的作用则是分别对applicationContext和BootstrapRegistry来进行预处理,而BootstrapRegistry的作用则是体现在:当你需要创建一个 ApplicationContextInitializer
来定制应用上下文,但这个Initializer的逻辑依赖于一个特定的组件(例如,一个高级的 Decryptor
解密器用来解密数据库密码)。然而,这个 Decryptor
本身又可能依赖于Spring的环境配置(Environment
),而 Environment
又是在ApplicationContext创建过程中才被完全初始化的。
这就形成了一个 启动阶段的循环依赖:
想创建
ApplicationContext
→ 需要先执行ApplicationContextInitializer
想执行
ApplicationContextInitializer
→ 需要先有Decryptor
实例想创建
Decryptor
实例 → 又需要Environment
(它又来自于ApplicationContext
)
BootstrapRegistry
的解决方案:
BootstrapRegistry
允许你在一切开始之前(在任何一个 ApplicationContextInitializer
执行之前),就通过 BootstrapRegistryInitializer
将像 Decryptor
这样的关键组件作为完全实例化的对象注册到一个临时的“工具箱”里。
因此BootstrapRegistry
是启动引导器,负责在最前期提供现成的工具实例。
BeanDefinitionRegistry
对于BeanDefinitionRegistry 的实例化则是在BeanDefinitionRegistryPostProcessor的处理类当中的postProcessBeanDefinitionRegistry来对其进行实例化处理的。
角色:IoC 容器的建筑师。
定位:它是 Spring Framework 中
ApplicationContext
的核心接口,负责持有所有 Bean 的“蓝图”(BeanDefinition
)。ApplicationContext
会根据这些蓝图来实例化、组装和管理所有的Bean。它是Spring IoC容器的心脏。它定义了应用程序中所有组件的基本信息,但并不负责实例化,而是为后续的实例化、依赖注入提供元数据。它是正式舞台的后台策划。
也就是说当前容器内的bean所有信息都会放到BeanDefinitionRegistry 中来进行处理,BootstrapRegistry
的生命周期早于 BeanDefinitionRegistry
。前者为后者的初始化过程提供支持,通常通过 ApplicationContextInitializer
将 BootstrapRegistry
中的实例“转移”或“注册”到 BeanDefinitionRegistry
中,使其成为被IoC容器管理的正式Bean。
详细对比
维度 | BeanDefinitionRegistry | BootstrapRegistry |
---|---|---|
所属阶段 | ApplicationContext 阶段 (主阶段) | Bootstrap 阶段 (极早期) |
核心目的 | 注册Bean的定义信息 (BeanDefinition ),即如何创建Bean的蓝图。 | 注册和持有完全实例化的对象实例,为引导过程提供现成的工具。 |
注册内容 | BeanDefinition 对象(包含类名、作用域、属性值、初始化方法等元数据)。 | 任何类型的对象实例 (如 RestTemplate , Decryptor )。通过 Supplier 或 BootstrapRegistry.InstanceSupplier 延迟提供。 |
生命周期 | 持久。与 ApplicationContext 同生命周期,伴随整个应用运行。 | 短暂。仅在 Bootstrap 阶段有效。一旦 ApplicationContext 准备就绪,其使命基本完成,内容可被转移到正式容器中。 |
接口方法 | registerBeanDefinition(String beanName, BeanDefinition beanDefinition) removeBeanDefinition(String beanName) getBeanDefinition(String beanName) | register(Class<T> type, BootstrapRegistry.InstanceSupplier<T> instanceSupplier) register(Class<T> type, Supplier<T> supplier) isRegistered(Class<T> type) |
依赖解决 | 解决 Bean之间的循环依赖(通过三级缓存机制)。 | 解决 启动流程上的依赖问题(通过提前实例化关键对象,打破初始化顺序的僵局)。 |
获取方式 | 通过 ApplicationContext (即 BeanFactory ) 的 getBean() 方法获取最终Bean实例。 | 在 ApplicationContextInitializer 中,通过 BootstrapContext 的 get(Class<T> type) 方法获取预先注册的实例。 |
典型应用 | 注册所有由 @Component , @Bean , @Service 等注解定义的组件。 | Spring Cloud Config:在获取远端配置前注册安全的 RestTemplate 。自定义引导:提前注册解密器、自定义的 PropertySourceLoader 等。 |
设计模式 | 工厂模式:存储的是产品的设计图,需要时再根据图纸生产。 | 仓库模式:直接存储了准备好的产品,需要时直接取用。 |
BootstrapRegistry
和 BeanDefinitionRegistry
是 Spring Boot 为解耦复杂的启动过程、清晰划分职责而设计的两个互补的组件。它们并非竞争或替代关系,而是分别在不同的生命周期阶段、为解决不同层面的问题而协同工作的伙伴。