Spring 源码解析:prepareBeanFactory() 方法深度剖析与面试指南
引言
在 Spring 容器初始化的 refresh() 方法中,prepareBeanFactory() 是 obtainFreshBeanFactory() 后的关键步骤。它负责对 BeanFactory 进行基础配置,为后续的 Bean 实例化和依赖注入提供支持。本文通过源码逐行解析 prepareBeanFactory(),并总结高频面试考点。
一、prepareBeanFactory() 方法的作用
prepareBeanFactory() 是 BeanFactory 初始化后的核心配置阶段,主要完成以下任务:
- 设置
BeanFactory的基础属性(如类加载器、表达式解析器)。 - 注册环境相关的单例 Bean(如
Environment、系统属性、系统环境变量)。 - 添加
ApplicationContextAwareProcessor,处理Aware接口的回调。 - 忽略特定接口的自动注入(如
EnvironmentAware、ApplicationContextAware)。 - 注册可解析的依赖(如
BeanFactory、ApplicationContext)。 - 添加
ApplicationListenerDetector,检测并管理ApplicationListenerBean。
二、源码逐行解析
1. 方法入口与核心逻辑
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1. 设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 2. 设置表达式解析器(SPEL)
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 3. 注册属性编辑器注册器(用于类型转换)
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 4. 添加 ApplicationContextAwareProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 5. 忽略 Aware 接口的自动注入(由 Spring 容器处理)
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 6. 注册可解析的依赖(允许直接注入 BeanFactory 或 ApplicationContext)
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 7. 添加 ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 8. 注册环境相关的单例 Bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
2. 关键操作详解
-
类加载器与表达式解析器
setBeanClassLoader:确保 Bean 实例化时使用容器指定的类加载器。setBeanExpressionResolver:支持 SPEL 表达式(如#{...})的解析。
-
ApplicationContextAwareProcessor- 作用:处理
Aware接口(如BeanNameAware、ApplicationContextAware)的回调,在 Bean 初始化时注入相关依赖。 - 实现原理:通过
postProcessBeforeInitialization方法调用invokeAwareInterfaces()。
- 作用:处理
-
忽略
Aware接口的自动注入- 避免用户手动注入
ApplicationContextAware等接口的实现,这些接口由 Spring 容器自动处理。
- 避免用户手动注入
-
可解析的依赖注册
- 允许通过
@Autowired直接注入BeanFactory或ApplicationContext,例如:@Autowired private ApplicationContext context;
- 允许通过
-
ApplicationListenerDetector- 检测实现了
ApplicationListener接口的 Bean,并将其注册到容器的事件广播器中。
- 检测实现了
-
环境相关单例注册
- 将
Environment、系统属性、系统环境变量注册为单例 Bean,便于通过名称直接访问。
- 将
三、高频面试考点与答案
1. prepareBeanFactory() 的核心作用是什么?
- 答案:配置
BeanFactory的基础属性(类加载器、表达式解析器),注册关键组件(如Aware处理器、环境 Bean),为后续 Bean 实例化和依赖注入提供支持。
2. ApplicationContextAwareProcessor 的作用是什么?
- 答案:在 Bean 初始化前处理
Aware接口的回调,例如为实现了ApplicationContextAware的 Bean 注入ApplicationContext。
3. 为什么需要调用 ignoreDependencyInterface() 方法?
- 答案:防止用户手动注入
Aware接口的实现类(如ApplicationContextAware),这些接口的依赖由 Spring 容器自动处理。
4. 如何在 Bean 中直接注入 ApplicationContext?
- 答案:通过
@Autowired注入,因为ApplicationContext已被注册为可解析的依赖。
5. ApplicationListenerDetector 的职责是什么?
- 答案:检测实现了
ApplicationListener的 Bean,并将其添加到容器的事件广播器中,确保事件监听功能生效。
6. 如何扩展 BeanFactory 的配置?
- 答案:通过重写
prepareBeanFactory()方法,例如添加自定义的BeanPostProcessor或注册新的可解析依赖。
四、总结与扩展
- 设计模式:
ApplicationContextAwareProcessor体现了回调机制,BeanPostProcessor是典型的拦截器模式。 - 环境集成:通过注册
Environment和系统属性,Spring 实现了配置的统一管理。 - 扩展性:开发者可通过自定义
BeanPostProcessor或重写prepareBeanFactory()方法扩展容器行为。
附:典型面试题
Q: 如果自定义的 Aware 接口需要被 Spring 处理,应该怎么做?
A: 实现 BeanPostProcessor,在 postProcessBeforeInitialization 方法中手动调用接口方法。
Q: 为什么 ApplicationContext 可以被直接注入到 Bean 中?
A: 因为 prepareBeanFactory() 中通过 registerResolvableDependency() 将其注册为可解析的依赖。
Q: 如何禁用 ApplicationContextAwareProcessor?
A: 重写 prepareBeanFactory() 方法,移除默认添加的 ApplicationContextAwareProcessor(一般不推荐)。
通过深入理解 prepareBeanFactory(),开发者可以掌握 Spring 容器的初始化细节,灵活应对环境配置、依赖注入等场景。在面试中,结合源码和实际应用回答问题,将显著提升技术深度评价。