🌱 Bean 生命周期
完整生命周期 · 循环依赖与三级缓存 · 实例化/初始化/销毁的扩展点
1. Bean 的完整生命周期?(必背,按顺序)
- 实例化(Instantiation):构造器/工厂方法创建对象(创建时即检查循环依赖)
- 属性填充(Populate):@Autowired/@Resource/XML 注入依赖属性
- Aware 回调:BeanNameAware → BeanClassLoaderAware → BeanFactoryAware(可拿容器)
- BeanPostProcessor 前置:postProcessBeforeInitialization(如 @PostConstruct 之前的平台处理、ApplicationContextAware 注入)
- 初始化(Initialization):先 @PostConstruct 方法 → 再 InitializingBean.afterPropertiesSet() → 再自定义 init-method
- BeanPostProcessor 后置:postProcessAfterInitialization —— AOP 代理在这里生成(AbstractAutoProxyCreator 就是 BPP)
- 使用:代理对象放入容器(bean 引用实际是代理)
- 销毁:@PreDestroy → DisposableBean.destroy() → 自定义 destroy-method
记忆口诀:实例化 → 属性注入 → Aware → 前置处理器 → 初始化 → 后置处理器(AOP)→ 使用 → 销毁。
各阶段验证(按日志顺序)
@Component
class LifecycleDemo implements BeanNameAware, InitializingBean, DisposableBean {
@Autowired private SomeService service; // 2. 属性填充
@PostConstruct
void postConstruct() { log("3. @PostConstruct"); }
@Override public void setBeanName(String name) { log("2.5 BeanNameAware: " + name); }
@Override public void afterPropertiesSet() { log("4. InitializingBean"); }
@PreDestroy
void preDestroy() { log("7. @PreDestroy"); }
@Override public void destroy() { log("8. DisposableBean.destroy"); }
}
🎯 面试要点
- @PostConstruct/@PreDestroy 是 JSR-250 标准;InitializingBean 是 Spring 接口;init-method 是 XML/@Bean(initMethod) 配置——三选一,别混用
- AOP 代理生成发生在"初始化之后"的 BPP 后置阶段——所以 @PostConstruct 里调用被代理的方法不会走代理(自调用问题)
- prototype Bean 不执行销毁回调(容器不管理)
2. 什么是循环依赖?Spring 如何解决?(必考,三级缓存)
循环依赖:A 依赖 B,B 依赖 A(或更长的环)。Spring 能解决 singleton + 字段/Setter 注入的循环,无法解决构造器注入的循环。
三级缓存(DefaultSingletonBeanRegistry 三个 Map):
singletonObjects(一级):完整成品单例earlySingletonObjects(二级):提前暴露的半成品(已实例化未初始化)singletonFactories(三级):ObjectFactory 工厂——核心,getEarlyBeanReference() 在此执行,决定是否提前生成 AOP 代理
解决过程(A ↔ B):
- 创建 A:实例化 → 提前把 A 的工厂放入三级缓存 → 填充属性发现需要 B
- 创建 B:实例化 → 放入三级缓存 → 填充属性发现需要 A
- B 从三级缓存拿到 A 的早期引用(若 A 需要 AOP,此处生成代理)→ B 完成创建并进一级缓存
- A 继续填充 B 完成,最后进一级缓存
为什么必须有三级而不是二级?
// 三级缓存存的不是对象,是 ObjectFactory
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName));
// 关键:AOP 代理的生成时机
// 正常情况下:初始化完成后 BPP 后置阶段生成代理
// 循环依赖时:B 需要 A 的早期引用,此时 A 还未初始化,
// 但代理必须在"被引用前"生成,否则 B 拿到的是原生 A(无事务/切面)
// → 用 ObjectFactory 延迟到"真正被引用"那一刻才决定:
// 被引用 → getEarlyBeanReference 提前代理;未被引用 → 正常流程后置代理
🎯 面试要点
- 构造器注入循环 → 直接报错 BeanCurrentlyInCreationException(bean 尚未实例化完,无法提前暴露)
- @Lazy 构造器注入可打破循环(延迟到使用时才创建)
- Spring Boot 2.6+ 默认禁止循环依赖(启动报错),可 spring.main.allow-circular-references=true 放开(不推荐)
- 循环依赖是设计味道:抽离公共依赖或用事件解耦更优雅
3. BeanDefinition 是什么?Bean 是怎么被发现的?
BeanDefinition:Bean 的"配方"——类名、作用域、懒加载、初始化方法、属性值等元信息。容器不直接操作 Bean,而是先注册 BeanDefinition,再按配方实例化。
三种注册来源:
- XML:
<bean id="x" class="..."/>解析为 BeanDefinition - 注解扫描:
@ComponentScan扫描包 → ClassPathBeanDefinitionScanner 把带 @Component/@Service 等的类注册为 BeanDefinition - JavaConfig:@Bean 方法返回的对象也注册为 BeanDefinition
BeanDefinition 的常用属性
BeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClassName("com.demo.UserService");
bd.setScope(BeanDefinition.SCOPE_SINGLETON);
bd.setLazyInit(false);
bd.setInitMethodName("init"); // init-method
bd.setPropertyValues(...); // 属性值
registry.registerBeanDefinition("userService", bd);
🎯 面试要点
- BeanDefinitionRegistry 负责注册,BeanFactory 负责按配方创建
- Spring Boot 的自动配置本质也是注册大量 BeanDefinition(见 Boot 页)
- ImportBeanDefinitionRegistrar:编程式注册 Bean 的扩展点(MyBatis 的 MapperScannerRegistrar 就是它)