一、引言:摸鱼时的灵魂拷问
"嘿,摸鱼刷手机,突然想到面试官上次问 Spring Bean 的生命周期,当时支支吾吾没答好。现在得补补,不然下次面试又栽跟头。咱用大白话聊聊,就当摸鱼学习了。"
二、Bean 生命周期:从出生到死亡的 "剧本"
1. 实例化(new 对象)
-
大白话 :Spring 先给 Bean "生" 出来,调用构造方法,就像
new UserService()
,这是第一步。 -
代码举例:
csharppublic class UserService { public UserService() { System.out.println("UserService实例化(构造方法)"); } }
2. 属性注入(填属性)
-
大白话 :给刚生的 Bean "穿衣服",把依赖的其他 Bean 或配置值塞进去。比如
@Autowired
注入 DAO,或者 XML 里的<property>
。 -
代码举例:
kotlinpublic class UserService { @Autowired private UserDAO userDAO; // 注入属性 }
3. 初始化前(BeanPostProcessor 预处理)
-
大白话:Spring 的 "前置处理器" 先检查 Bean,搞点 AOP 代理啥的(比如事务增强)。这时候 Bean 还没完全初始化,先 "整整容"。
-
代码举例(BeanPostProcessor) :
typescriptpublic class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("初始化前处理:" + beanName); return bean; } }
4. 初始化(自己的初始化逻辑)
-
大白话 :Bean 自己的 "初始化仪式",比如实现
InitializingBean
接口(afterPropertiesSet
方法),或者配置init-method
。这时候 Bean 终于 "ready" 了。 -
代码举例(InitializingBean) :
csharppublic class UserService implements InitializingBean { @Override public void afterPropertiesSet() { System.out.println("UserService初始化(afterPropertiesSet)"); } } // 或者XML配置init-method:<bean init-method="init"/> public void init() { System.out.println("自定义初始化方法"); }
5. 初始化后(BeanPostProcessor 后处理)
-
大白话:"后置处理器" 再检查一遍,比如生成最终的代理对象(AOP 的最后一步)。这时候 Bean 完全 "打扮好",可以用了。
-
代码举例(BeanPostProcessor) :
typescript@Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("初始化后处理:" + beanName); return bean; // 比如返回代理后的Bean }
6. 使用(被调用)
- 大白话:Bean 开始 "干活",比如处理 HTTP 请求、执行业务逻辑,这是它的 "职业生涯"。
7. 销毁(容器关闭时清理)
-
大白话 :Spring 容器关闭时,Bean "退休",执行销毁逻辑。比如实现
DisposableBean
(destroy
方法),或配置destroy-method
,释放资源(比如数据库连接)。 -
代码举例(DisposableBean) :
csharppublic class UserService implements DisposableBean { @Override public void destroy() { System.out.println("UserService销毁(destroy)"); } } // 或者XML配置destroy-method:<bean destroy-method="destroy"/> public void destroy() { System.out.println("自定义销毁方法"); }
三、核心代码串起来(XML 配置示例,简单明了)
ini
<beans>
<bean id="userService" class="com.example.UserService"
init-method="init" destroy-method="destroy">
<property name="userDAO" ref="userDAO"/>
</bean>
<bean class="com.example.MyBeanPostProcessor"/>
</beans>
- 执行顺序:构造→注入→初始化前→init 方法→初始化后→使用→destroy 方法(容器关闭时)。
四、实际场景:这玩意儿有啥用?
- AOP 实现:BeanPostProcessor 在初始化前后生成代理(比如事务切面),这就是 Spring AOP 的底层逻辑。
- 资源初始化 / 销毁:比如数据库连接池在初始化时创建连接,销毁时关闭(用 init-method 和 destroy-method)。
- 参数校验:初始化前检查 Bean 的属性是否合法(比如 @Validated 注解的处理,类似 BeanPostProcessor 的逻辑)。
- 框架扩展 :比如 MyBatis 的
SqlSessionFactoryBean
,在初始化时解析 XML,创建 SqlSessionFactory(用 afterPropertiesSet 方法)。
五、面试官为啥总问?
- 考察 Spring 核心理解:Bean 生命周期是 Spring 容器的核心机制,懂了它,才知道 Spring 如何管理对象,为啥能实现依赖注入、AOP 这些功能。
- 排查问题能力:比如 Bean 初始化失败(比如 init-method 抛异常),懂生命周期才能快速定位(是注入错了?还是初始化逻辑有问题?)。
- 框架扩展能力:如果你要写自定义 Spring Starter(比如集成 Redis),需要在 Bean 生命周期的某个阶段注册组件(比如初始化后创建 Redis 连接),这时候必须懂生命周期。
六、摸鱼总结
"原来 Bean 的生命周期就是这么个流程!现在再被面试官问,能从实例化到销毁,一步步说清楚。下次写代码时,遇到 Bean 初始化的问题,也知道从哪个阶段排查。摸鱼学技术,真香!"