深入解析 Spring Bean 生命周期:从 IoC 到实际应用的全面指南,助你在阿里云面试中脱颖而出
Spring Bean 的生命周期是面试中经常被询问的话题。最近有位读者在面试中未能回答这一问题,导致未通过第一轮。因此,了解这一主题是非常重要的。
为了让文章更具深度,我将内容分为两个主要部分:第一部分涵盖基础知识,帮助大家应对面试,第二部分则深入源码分析,适合对源码感兴趣的读者。
接下来,我们将详细探讨内容大纲。
1. 基础知识
1.1 理解 IoC
IoC(控制反转)是一个重要的概念,它意味着容器负责创建和管理对象,而不是由程序主动创建。此过程体现了面向对象设计中的“好莱坞法则”:“别找我们,我们会找你”。IoC 容器会帮助对象获取所需的依赖,而非由对象主动寻找。
要充分理解 IoC,需要明确以下几个问题:控制关系、控制对象及其反转的原因。
控制关系:
在传统的 Java SE 编程中,我们通过 new
关键字主动创建对象,程序控制对象的创建。而在 IoC 模型中,容器负责这一过程,主动管理对象的生命周期。
- 谁控制谁? IoC 容器控制对象的创建。
- 控制的内容是什么? 不仅限于对象的创建,还包括对外部资源的管理。
为何称之为反转:
反转是相对于传统的直接创建方式而言的。在传统应用中,我们主动控制对象的创建,而在 IoC 中,容器负责对象的查找和注入,形成了“反转”的关系。
1.2 Bean 生命周期
对于原型(Prototype)Bean,当用户通过 getBean
方法获取一个实例时,IoC 容器将不再管理该实例的生命周期,因此实际描述 Bean 生命周期时,主要指的是单例(Singleton)Bean。
Bean 生命周期的主要过程包括:
- 实例化:创建 Bean 对象。
- 属性赋值:为 Bean 设置属性和依赖。
- 初始化:包括多个步骤,从前期准备到后期的初始化,完成后 Bean 可被使用。
- 销毁:注册销毁方法,以便在实际销毁时执行清理操作。
整个执行流程可能较为抽象,接下来通过代码进行演示。
1.3 执行流程
创建一个 LouzaiBean
类。
public class LouzaiBean implements InitializingBean, BeanFactoryAware, BeanNameAware, DisposableBean {
private String name;
public LouzaiBean() {
System.out.println("1.调用构造方法:我出生了!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("2.设置属性:我的名字叫" + name);
}
@Override
public void setBeanName(String s) {
System.out.println("3.调用BeanNameAware#setBeanName方法:我要上学了,起了个学名");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4.调用BeanFactoryAware#setBeanFactory方法:选好学校了");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6.InitializingBean#afterPropertiesSet方法:入学登记");
}
public void init() {
System.out.println("7.自定义init方法:努力上学ing");
}
@Override
public void destroy() throws Exception {
System.out.println("9.DisposableBean#destroy方法:平淡的一生落幕了");
}
public void destroyMethod() {
System.out.println("10.自定义destroy方法:睡了,别想叫醒我");
}
public void work() {
System.out.println("Bean使用中:工作,只有对社会没有用的人才放假。。");
}
}
自定义一个后处理器 MyBeanPostProcessor
。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5.BeanPostProcessor.postProcessBeforeInitialization方法:到学校报名啦");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("8.BeanPostProcessor#postProcessAfterInitialization方法:终于毕业,拿到毕业证啦!");
return bean;
}
}
applicationContext.xml
配置文件(部分)。
<bean name="myBeanPostProcessor" class="demo.MyBeanPostProcessor" />
<bean name="louzaiBean" class="demo.LouzaiBean" init-method="init" destroy-method="destroyMethod">
<property name="name" value="楼仔" />
</bean>
测试入口:
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
LouzaiBean louzaiBean = (LouzaiBean) context.getBean("louzaiBean");
louzaiBean.work();
((ClassPathXmlApplicationContext) context).destroy();
}
}
执行结果:
1.调用构造方法:我出生了!
2.设置属性:我的名字叫楼仔
3.调用BeanNameAware#setBeanName方法:我要上学了,起了个学名
4.调用BeanFactoryAware#setBeanFactory方法:选好学校了
5.BeanPostProcessor.postProcessBeforeInitialization方法:到学校报名啦
6.InitializingBean#afterPropertiesSet方法:入学登记
7.自定义init方法:努力上学ing
8.BeanPostProcessor#postProcessAfterInitialization方法:终于毕业,拿到毕业证啦!
Bean使用中:工作,只有对社会没有用的人才放假。。
9.DisposableBean#destroy方法:平淡的一生落幕了
10.自定义destroy方法:睡了,别想叫醒我
通过上面的执行流程,Bean 生命周期的每个步骤都十分清晰。
1.4 扩展方法
Bean 生命周期的扩展主要分为四个类别:
- Aware 接口:允许 Bean 获取容器的资源,例如
BeanNameAware
的setBeanName()
和BeanFactoryAware
的setBeanFactory()
。 - 后处理器:提供初始化前后的处理,例如
BeanPostProcessor
的前置和后置方法。 - 生命周期接口:定义初始化和销毁方法,例如
InitializingBean
的afterPropertiesSet()
和DisposableBean
的destroy()
。 - 配置生命周期方法:通过配置文件自定义初始化和销毁方法,例如
init()
和destroyMethod()
。
2. 源码解读
注意:本示例基于 5.2.15.RELEASE 版本的 Spring,其他版本可能存在差异。
接下来,我们将深入探讨代码的执行流程。
2.1 代码入口
这里需要多次运行,跳过前面的 beanName 只关注 louzaiBean
。
进入 doGetBean()
,在 getSingleton()
中未找到对象,转入创建 Bean 的逻辑。
2.2 实例化
进入 doCreateBean()
,调用 createBeanInstance()
。
2.3 属性赋值
返回 doCreateBean()
,进入 populateBean()
。这个方法实现了依赖注入的核心逻辑。
2.4 初始化
继续回到 doCreateBean()
,执行 initializeBean()
。
2.5 销毁
当 louzaiBean
创建后,销毁过程相对简单。进入示例 LouzaiBean
的方法,执行 destroy()
方法。
3. 写在最后
我们总结几个关键的方法:
- doCreateBean():整个生命周期的入口。
- createBeanInstance():用于 Bean 的初始化,调用构造方法。
- populateBean():实现属性的依赖注入和成员变量初始化。
- initializeBean():执行初始化相关方法及处理逻辑。
- destroy():执行销毁相关方法。
对于 populateBean()
,其核心在于对象的依赖注入,这是重要的面试知识点之一。