文章目录
- 前言
-
- 1. 理解bean的生命周期
- 2. Bean 生命周期的执行过程
- 3. Bean生命周期控制入门案例
- 4. 关闭IOC容器的两种方式
- 5. 通过继承接口绑定生命周期方法
- 总结
前言
为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。
(博客的参考源码以及可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)
1. 理解bean的生命周期
- 生命周期: 从创建到消亡的完整过程;bean生命周期 : bean从创建到销毁的整体过程; bean生命周期控制:在bean创建后到销毁前做一些事情
- 理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作
- 尽管还有一些在 Bean 实例化和销毁之间发生的活动,有两个重要的生命周期回调方法,它们在 bean 的初始化和销毁的时候是必需的
- 为了定义安装和拆卸一个 bean,我们只要声明带有 init-method 和/或 destroy-method 参数的 。init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。同样,destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法
- Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
2. Bean 生命周期的执行过程
- 根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean
- 利用依赖注入完成 Bean 中所有属性值的配置注入
- 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值
- 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用
- 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的
- 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法
- 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了
- 如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean
- 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁
- Spring 为 Bean 提供了细致全面的生命周期过程,通过实现特定的接口或 的属性设置,都可以对 Bean 的生命周期过程产生影响。虽然可以随意配置 的属性,但是建议不要过多地使用 Bean 实现接口,因为这样会导致代码和 Spring 的聚合过于紧密
3. Bean生命周期控制入门案例
1. 编写代码(IOC 和 DI入门案例的代码,模块名为respr_ioc)
- 在BookDaoImpl实现类中定义代表创建bena初始化和销毁的方法
package org.example.dao.impl;
import org.example.dao.BookDao;
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
2. 在applicationContext.xml文件中配置BookDao bean 的 初始化方法 int-method 和销毁方法 destory-method
3. 将BookService的代码注释掉,运行模拟测试类,观察BookDao bean的创建和销毁过程
4. 观察运行结果
5. 简要分析
- 我们从运行结果可以看到bean初始化成功了,但是并没有进行销毁工作,原因是java虚拟机(java在虚拟机运行)在执行玩程序退出时并没有做销毁操作,我们需要自己添加关闭语句,ctx.close()。
- 但是ApplicationContext接口中并没有这个方法,而它的实现类中有,所以我们要用它的实现类ClassPathXmlApplicationContext来调用这个方法
4. 关闭IOC容器的两种方式
1. 关闭ioc容器的代码及运行结果如下
2. 关闭ioc容器的第二种方式:关闭钩子(概念、代码及运行结果如下)
- 在Java程序退出时——尤其是非正常退出时,我们可能需要先执行一些善后工作,如关闭线程池、连接池、文件句柄等。
- 如何保证善后工作的代码能够被执行到呢?Java为用户提供了关闭钩子(shutdown hook)registerShutdownHook()方法来注册关闭钩子
3. 两种关闭ioc容器的简要分析
关闭钩子函数代码在程序中的位置要求没有close()方法那么苛刻,如果将其挪到bookDao.save()方法的下面也能用,close()方法比较暴力
5. 通过继承接口绑定生命周期方法
1. 绑定销毁方法和初始化方法的改进–继承接口(以BookServiceImpl为例)
- 实现InitializingBean, DisposableBean接口
- 重写 destroy(销毁) 和 afterPropertiesSet(初始化) 方法
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
2. 模拟测试类Main2运行结果
尽管在模拟测试类Main2并没有调用BookService 的bean,但是在核心配置文件中定义了BookService 的 bean,该创建bean的时候就创建,该初始化就初始化,该销毁就销毁
总结
欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)