一:简述
那什么是 Bean 的⽣命周期呢?这是⾮常基础的问题,面试过程中也经常会被问到。
二. 基础知识
2.1 什么是 IoC ?
IoC,控制反转,想必⼤家都知道,所谓的控制反转,就是把 new 对象的权利交给容器,所有的对象都被容器控 制,这就叫所谓的控制反转。
IoC 很好地体现了⾯向对象设计法则之⼀ —— 好莱坞法则:“别找我们,我们找你”,即由 IoC 容器帮对象找相应的 依赖对象并注⼊,⽽不是由对象主动去找。
理解好 IoC 的关键是要明确 “谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些⽅⾯反转了”。
谁控制谁,控制什么?
传统 Java SE 程序设计,我们直接在对象内部通过 new 进⾏创建对象,是程序主动去创建依赖对象。⽽ IoC 是由专 ⻔⼀个容器来创建这些对象,即由 IoC 容器来控制对象的创建。
- 谁控制谁?当然是 IoC 容器控制了对象;
- 控制什么?主要控制了外部资源获取(不只是对象,⽐如包括⽂件等)。
为何是反转,哪些⽅⾯反转了?
有反转就有正转,传统应⽤程序是由我们⾃⼰在对象中主动控制去直接获取依赖对象,也就是正转,⽽反转则是由 容器来帮忙创建及注⼊依赖对象。
- 为何是反转?因为由容器帮我们查找及注⼊依赖对象,对象只是被动的接受依赖对象,所以是反转;
- 哪些⽅⾯反转了?依赖对象的获取被反转了。
2.2 Bean ⽣命周期
对 Prototype Bean 来说,当⽤户 getBean 获得 Prototype Bean 的实例后,IOC 容器就不再对当前实例进⾏管 理,⽽是把管理权交由⽤户,此后再 getBean ⽣成的是新的实例。
所以我们描述 Bean 的⽣命周期,都是指的 Singleton Bean。
Bean ⽣命周期过程:
- 实例化:第 1 步,实例化⼀个 Bean 对象;
- 属性赋值:第 2 步,为 Bean 设置相关属性和依赖;
- 初始化:初始化的阶段的步骤⽐较多,5、6 步是真正的初始化,第 3、4 步为在初始化前执⾏,第 7 步在初 始化后执⾏,初始化完成之后,Bean 就可以被使⽤了;
- 销毁:第 8~10 步,第 8 步其实也可以算到销毁阶段,但不是真正意义上的销毁,⽽是先在使⽤前注册了销毁 的相关调⽤接⼝,为了后⾯第 9、10 步真正销毁 Bean 时再执⾏相应的⽅法。
整个执⾏流程稍微有些抽象,下⾯我们通过代码,来演示执⾏流程。
2.3 执⾏流程
创建⼀个 ModelBean。
public class ModelBean implements InitializingBean, BeanFactoryAware, BeanNameAware,
DisposableBean {
/**
* 姓名
*/
private String name;
public ModelBean() {
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="model" />
</bean>
复制代码
测试⼊⼝:
public class MyTest {
public static void main(String[] args) {
ApplicationContext context =new
ClassPathXmlApplicationContext("classpath:applicationContext.xml");
LouzaiBean modelBean = (ModelBean) context.getBean("modelBean");
louzaiBean.work();
((ClassPathXmlApplicationContext) context).destroy();
}
}
复制代码
执⾏结果:
- 1.调⽤构造⽅法:我出⽣了!
- 2.设置属性:我的名字叫model
- 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 ⽣命周期流程图能完全对应起来。
2.4 扩展⽅法
我们发现,整个⽣命周期有很多扩展过程,⼤致可以分为 4 类:
- Aware 接⼝:让 Bean 能拿到容器的⼀些资源,例如 BeanNameAware 的 setBeanName(), BeanFactoryAware 的 setBeanFactory();
- 后处理器:进⾏⼀些前置和后置的处理,例如 BeanPostProcessor 的 postProcessBeforeInitialization() 和 postProcessAfterInitialization();
- ⽣命周期接⼝:定义初始化⽅法和销毁⽅法的,例如 InitializingBean 的 afterPropertiesSet(),以及 DisposableBean 的 destroy();
- 配置⽣命周期⽅法:可以通过配置⽂件,⾃定义初始化和销毁⽅法,例如配置⽂件配置的 init() 和 destroyMethod()。
三. 源码解读
注意:Spring 的版本是 5.2.15.RELEASE,否则和我的代码不⼀样!!!
上⾯的知识,⽹上其实都有,下⾯才是我们的干货,让你跟着我⾛⼀遍代码流程。
3.1 代码⼊⼝
这⾥需要多跑⼏次,把前⾯的 beanName 跳过去,只看 modelBean。
进⼊ doGetBean(),从 getSingleton() 没有找到对象,进⼊创建 Bean 的逻辑。
3.2 实例化
进⼊ doCreateBean() 后,调⽤ createBeanInstance()。
进⼊ createBeanInstance() 后,调⽤ instantiateBean()。
⾛进示例 LouzaiBean 的⽅法,实例化 LouzaiBean。
3.3 属性赋值
再回到 doCreateBean(),继续往后⾛,进⼊ populateBean()。
这个⽅法⾮常重要,⾥⾯其实就是依赖注⼊的逻辑,不过这个不是我们今天的重点,⼤家如果对依赖注⼊和 循环依赖感兴趣,可以翻阅我之前的⽂章。
进⼊ populateBean() 后,执⾏ applyPropertyValues()
进⼊ applyPropertyValues(),执⾏ bw.setPropertyValues()
进⼊ processLocalProperty(),执⾏ ph.setValue()。
⾛进示例 ModelBean 的⽅法,给 ModelBean 赋值 name。
到这⾥,populateBean() 就执⾏完毕,下⾯开始初始化 Bean。
3.4 初始化
我们继续回到 doCreateBean(),往后执⾏ initializeBean()。
⾛进示例 ModelBean 的⽅法,给 ModelBean 设置 BeanName。
回到 invokeAwareMethods()。
⾛进示例 ModelBean 的⽅法,给 ModelBean 设置 BeanFactory。
第⼀次回到 initializeBean(),执⾏下⾯逻辑。
这⾥需要多循环⼏次,找到 MyBeanPostProcessor 的策略⽅法。
我们⾃⼰定义的后置处理⽅法。
第⼆次回到 initializeBean() ,执⾏下⾯逻辑。
⾛进示例 LouzaiBean 的⽅法,执⾏ afterPropertiesSet()。
返回 invokeInitMethods(),执⾏下⾯逻辑。
进⼊ invokeCustomInitMethod(),执⾏下⾯逻辑。
⾛进示例 ModelBean 的⽅法,执⾏ init()。
第三次回到 initializeBean(),执⾏下⾯逻辑。
我们⾃⼰定义的后置处理⽅法。
到这⾥,初始化的流程全部结束,都是围绕 initializeBean() 展开。
3.4 销毁
当 mdoelBean ⽣成后,后⾯开始执⾏销毁操作,整个流程就⽐较简单。
⾛进示例 ModelBean 的⽅法,执⾏ destroy()。
回到 destroy(),执⾏下⾯逻辑。
⾛进示例 ModelBean 的⽅法,执⾏ destroyMethod()。
到这⾥,所有的流程全部结束,⽂章详细描述所有的代码逻辑流转,你可以完全根据上⾯的逻辑,⾃⼰ debug ⼀ 遍,相信印象会更加深刻。
四. 都要总结哦哦哦哦
我们再回顾⼀下⼏个重要的⽅法:
- doCreateBean():这个是⼊⼝;
- createBeanInstance():⽤来初始化 Bean,⾥⾯会调⽤对象的构造⽅法;
- populateBean():属性对象的依赖注⼊,以及成员变量初始化;
- initializeBean():⾥⾯有 4 个⽅法,
- 先执⾏ aware 的 BeanNameAware、BeanFactoryAware 接⼝;
- 再执⾏ BeanPostProcessor 前置接⼝;
- 然后执⾏ InitializingBean 接⼝,以及配置的 init();
- 最后执⾏ BeanPostProcessor 的后置接⼝。
- destory():先执⾏ DisposableBean 接⼝,再执⾏配置的 destroyMethod()。
对于 populateBean(),⾥⾯的核⼼其实是对象的依赖注⼊,这⾥也是常考的知识点,⽐如循环依赖等。