Spring IoC容器初始化流程
约 1411 字大约 5 分钟
springioc
2025-03-21
概述
Spring IoC(Inversion of Control)容器是 Spring 框架的核心基础设施。它负责创建、配置和管理 Bean 的完整生命周期。理解 IoC 容器的初始化流程,是掌握 Spring 框架底层原理的关键。
本文将深入剖析从 ApplicationContext 创建到所有 Bean 就绪的完整流程,涵盖 BeanFactory、BeanDefinition、BeanFactoryPostProcessor、BeanPostProcessor 等核心组件。
容器初始化总体流程
ApplicationContext 的层次结构
Spring 提供了多种 ApplicationContext 实现,适用于不同场景:
核心组件解析
1. BeanFactory —— Bean 工厂
BeanFactory 是 Spring 容器的根接口,提供最基础的 Bean 获取能力。DefaultListableBeanFactory 是其最核心的实现类,承载了 Bean 定义的注册与管理。
// 直接使用 BeanFactory(底层API,通常不直接使用)
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 通常使用 ApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);2. BeanDefinition —— Bean 定义
BeanDefinition 描述了一个 Bean 的元数据信息,包括类名、作用域、构造参数、属性值、初始化方法等。
// 编程方式注册 BeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
beanDefinition.setLazyInit(false);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// 注册到 BeanFactory
beanFactory.registerBeanDefinition("userService", beanDefinition);3. BeanDefinition 注册流程
refresh() 核心方法详解
AbstractApplicationContext.refresh() 是容器初始化的核心方法,包含 13 个步骤:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新:设置启动时间、活动标志、初始化属性源
prepareRefresh();
// 2. 获取新的 BeanFactory(解析XML/注解,加载BeanDefinition)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备 BeanFactory:注册内置Bean、设置类加载器等
prepareBeanFactory(beanFactory);
try {
// 4. 子类扩展点:可以注册特殊的BeanPostProcessor
postProcessBeanFactory(beanFactory);
// 5. 调用所有已注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor(拦截Bean创建过程)
registerBeanPostProcessors(beanFactory);
// 7. 初始化国际化消息源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 子类扩展点(如SpringBoot内嵌Web容器)
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 实例化所有非懒加载的单例Bean(核心步骤)
finishBeanFactoryInitialization(beanFactory);
// 12. 发布ContextRefreshedEvent
finishRefresh();
} catch (BeansException ex) {
destroyBeans();
cancelRefresh(ex);
throw ex;
}
}
}BeanFactoryPostProcessor
BeanFactoryPostProcessor 在所有 BeanDefinition 加载完成后、Bean 实例化之前被调用,用于修改 BeanDefinition 的属性。
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
// 获取指定 BeanDefinition 并修改
BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
MutablePropertyValues pvs = bd.getPropertyValues();
pvs.addPropertyValue("maxPoolSize", 50);
// 也可以动态注册新的 BeanDefinition
if (beanFactory instanceof BeanDefinitionRegistry registry) {
GenericBeanDefinition newBd = new GenericBeanDefinition();
newBd.setBeanClass(MonitorService.class);
registry.registerBeanDefinition("monitorService", newBd);
}
}
}BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的子接口,执行时机更早,可以注册额外的 BeanDefinition:
@Component
public class CustomRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 在标准 BFPP 之前执行,可注册新的 BeanDefinition
RootBeanDefinition bd = new RootBeanDefinition(AuditService.class);
registry.registerBeanDefinition("auditService", bd);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 在 postProcessBeanDefinitionRegistry 之后执行
}
}BeanPostProcessor
BeanPostProcessor 在 Bean 实例化之后、初始化前后被调用,用于对 Bean 实例进行增强处理(如 AOP 代理就是通过 BPP 实现的)。
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof DataSource) {
System.out.println("DataSource Bean 初始化之前: " + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof UserService) {
// 可以返回代理对象替换原始Bean
System.out.println("UserService Bean 初始化之后: " + beanName);
}
return bean;
}
}BFPP 与 BPP 的执行时序
SpringBoot 中的容器启动
SpringBoot 通过 SpringApplication.run() 驱动容器初始化,额外引入了 ApplicationContextInitializer 和自动配置机制:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// run() 内部创建 ApplicationContext 并调用 refresh()
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
// 获取Bean
UserService userService = context.getBean(UserService.class);
}
}常见问题与调试技巧
1. 查看所有已注册的 BeanDefinition
@Component
public class BeanDefinitionPrinter implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
ConfigurableListableBeanFactory beanFactory =
((ConfigurableApplicationContext) applicationContext).getBeanFactory();
String[] names = beanFactory.getBeanDefinitionNames();
for (String name : names) {
BeanDefinition bd = beanFactory.getBeanDefinition(name);
System.out.printf("Bean: %s, class: %s, scope: %s%n",
name, bd.getBeanClassName(), bd.getScope());
}
}
}2. 容器启动慢的排查
开启 Spring 启动耗时统计:
# application.properties
spring.main.startup-info=true
logging.level.org.springframework.boot.autoconfigure=DEBUG使用 ApplicationStartup 记录详细启动步骤:
SpringApplication app = new SpringApplication(MyApplication.class);
app.setApplicationStartup(new BufferingApplicationStartup(2048));
app.run(args);总结
Spring IoC 容器初始化是一个严谨有序的过程:加载 BeanDefinition → 调用 BeanFactoryPostProcessor 修改定义 → 注册 BeanPostProcessor → 实例化并初始化所有单例 Bean。理解这个流程有助于定位 Bean 创建异常、循环依赖、配置未生效等常见问题,也为编写自定义扩展(如自定义 Starter、框架集成)提供了理论基础。
贡献者
更新日志
9f6c2-feat: organize wiki content and refresh site setup于