Spring Bean 生命周期:搞懂这 8 步,面试再也不怕被问 目录一、完整流程图二、每个阶段实际在干嘛① 实例化 — Spring 通过反射 new 对象② 属性注入 — Autowired/Value 填值③ Aware 回调 — Spring 告诉你你是谁④ BeanPostProcessor.Before — 初始化前拦截⑤ 初始化 — 真正的干活阶段三步走⑥ BeanPostProcessor.After — AOP 代理就在这里⑧ 销毁 — 容器关闭时的善后三步走三、默认执行 vs 需要主动配置 默认执行的你不写任何代码也会走 需要你主动写代码才会触发的四、初始化前后的 BeanPostProcessor 作用五、一句话总结全流程六、面试高频点七、面试话术八、验证代码一、完整流程图二、每个阶段实际在干嘛① 实例化 — Spring 通过反射 new 对象// Spring 做的事new UserService() // 这时候所有属性都是 null 或默认值 UserService userService new UserService(); ​ // 打印出来是 dbUrl null ← Value 还没注入 maxActive 0 ← Value 还没注入 configLoader null ← Autowired 还没注入实际意义千万别在构造方法里调用这些属性会报空指针。② 属性注入 — Autowired/Value 填值Autowired private ConfigLoader configLoader; // 这时候才注入 Value(${db.url}) private String dbUrl; // 这时候才注入 ​ // 到 PostConstruct 时值已经正常了 dbUrl jdbc:mysql://localhost:3306/userdb ← 不再是 null configLoader ConfigLoader{versionv2.3.1...} ← 不再是 null实际意义你的Autowired、Value都在这里生效。③ Aware 回调 — Spring 告诉你你是谁setBeanName → 我叫 userService setBeanFactory → 我已经能看到容器里有其他 Bean 了 setApplicationContext → 容器里一共 9 个 Bean实际意义BeanNameAware→ 项目中几乎不用ApplicationContextAware→ 极少数项目用来手动获取 Bean④ BeanPostProcessor.Before — 初始化前拦截实际意义Spring 自己用它来解析Autowired、Value等注解。⑤ 初始化 — 真正的干活阶段三步走执行顺序方式代码你要怎么写①PostConstruct方法上加注解方法上加PostConstruct②InitializingBean实现接口重写afterPropertiesSet()implements InitializingBean③init-method在Bean里指定方法名Bean(initMethodxxx)实际用途启动资源创建数据库连接池、启动定时任务校验配置检查必要属性是否都注入了预热数据从数据库加载热点数据到内存⑥ BeanPostProcessor.After — AOP 代理就在这里实际意义如果你给 UserService 加了Transactional这步会返回一个CGLIB 代理对象而不是原始对象。这就是为什么Transactional只在通过 Spring 容器获取的 Bean 上生效。⑧ 销毁 — 容器关闭时的善后三步走执行顺序方式代码你要怎么写①PreDestroy方法上加注解方法上加PreDestroy②DisposableBean实现接口重写destroy()implements DisposableBean③destroy-method在Bean里指定方法名Bean(destroyMethodxxx)实际用途关闭线程池、断开数据库连接、保存未处理的消息。三、默认执行 vs 需要主动配置 默认执行的你不写任何代码也会走实例化只要声明了Component/Bean就会走属性注入只要有Autowired、Value就会注入AOP 代理Spring Boot 默认自带加Transactional就生效 需要你主动写代码才会触发的扩展点你要怎么写平时用过吗BeanNameAwareimplements BeanNameAware❌ 几乎不用ApplicationContextAwareimplements ApplicationContextAware⚠️ 极少数项目用BeanPostProcessorimplements BeanPostProcessor并注册❌ 没用过PostConstruct方法上加注解✅ 最常用PreDestroy方法上加注解⚠️ 偶尔InitializingBeanimplements InitializingBean❌ 很少直接用initMethodBean(initMethodxxx)❌ 很少直接用你日常开发里 99% 的 Bean 生命周期就是① 实例化 → ② 属性注入 → ③ 就绪 ↘ 如果加了 PostConstruct中间插一步 ↘ 如果加了 Transactional最后变成代理对象四、初始化前后的 BeanPostProcessor 作用阶段一句话作用初始化属性注入完成后Bean 还需要做点什么准备才能真正干活启动连接池、校验配置、加载缓存初始化前拦截Spring 在初始化之前插入一个卡点让你可以预处理Spring 自己用它解析Autowired初始化后拦截Bean 初始化完成后拦截器可以替换整个对象AOP 代理就是在这里把原始对象替换成代理对象的五、一句话总结全流程new出来空的 ↓ 填依赖Autowired生效 ↓ 告诉我你是谁Aware ↓ 初始化前BeanPostProcessor ✋ ↓ PostConstruct → 准备资源 afterPropertiesSet → 检查配置 init-method → 加载缓存 ↓ 初始化后AOP代理就在这里 ↓ 可以用了调业务方法 ↓ 容器关闭 → PreDestroy → destroy → destroy-method → 释放资源六、面试高频点问题答案AOP 代理什么时候创建的BeanPostProcessor.postProcessAfterInitialization()中Autowired 在哪工作的属性注入阶段由AutowiredAnnotationBeanPostProcessor处理PostConstruct vs InitializingBean 谁先PostConstruct先prototype 会被销毁吗不会Spring 只管理 singleton 的销毁BeanPostProcessor 可以用几个多个按Ordered接口排序执行Spring Boot 默认用什么代理CGLIBspring.aop.proxy-target-classtrue七、面试话术问Bean 有哪几种初始化方式执行顺序是什么有三种按顺序执行PostConstruct注解方式—— 方法上加注解InitializingBean接口方式—— 实现接口重写afterPropertiesSet()init-method配置方式—— 在Bean(initMethodxxx)里指定其中最常用的是PostConstruct因为它最简单——加个注解就行。 顺序是固定的由 Spring 源码AbstractAutowireCapableBeanFactory.doCreateBean()决定。 实际开发中90% 的场景只需要用PostConstruct就够了。问BeanPostProcessor 的 Before 和 After 有什么区别Before初始化前Spring 自己用它来解析Autowired、Value等注解After初始化后这是 AOP 创建代理对象的地方。如果你加了TransactionalSpring 在这步把原始 Bean 替换成 CGLIB 代理对象一句话总结Before 是给 Spring 自己用的After 是给 AOP 用的。八、验证代码代码项目在本账号的仓库中bean-init-demo可以直接运行预期输出如下【构造方法】MyService 被 new 出来了还没注入属性 【属性注入】name 被设置了温度监控服务 ​ 【方式一 · PostConstruct】我执行了 ← 第一个执行 【方式二 · InitializingBean】我执行了 ← 第二个执行 【方式三 · init-method配置】我执行了 ← 第三个执行 ​ 【业务】MyService 在干活name温度监控服务 ​ 【销毁一 · PreDestroy】我执行了 ← 第一个销毁 【销毁二 · DisposableBean】我执行了 ← 第二个销毁 【销毁三 · destroy-method】我执行了 ← 第三个销毁