详解 Spring 中 Bean 的作用域与生命周期
摘要:在利用 Spring 进行 IOC 配置时,关于 bean 的配置和使用一直都是比较重要的一部分,同时如何正当的使用和创立 bean 对象,也是小伙伴们在学习和使用 Spring 时需要注意的部分,所以这一篇文章我就来和大家讲一下有关 Spring 中 bean 的作用域和其生命周期。
本文分享自华为云社区《详解Spring中Bean的作用域与生命周期》,原文作者:灰小猿。
在利用 Spring 进行 IOC 配置时,关于 bean 的配置和使用一直都是比较重要的一部分,同时如何正当的使用和创立 bean 对象,也是小伙伴们在学习和使用 Spring 时需要注意的部分,所以这一篇文章我就来和大家讲一下有关 Spring 中 bean 的作用域和其生命周期。
一、Bean 的作用域
首先我们来讲一下有关于 bean 的作用域
一般情况下,我们书写在 IOC 容器中的配置信息,会在我们的 IOC 容器运行时被创立,这就导致我们通过 IOC 容器获取到 bean 对象的时候,往往都是获取到了单实例的 Bean 对象
这样就意味着无论我们使用多少个 getBean()方法,获取到的同一个 JavaBean 都是同一个对象,这就是单实例 Bean,整个项目都会共享这一个 bean 对象。
在 Spring 中,可以在元素的 scope 属性里设置 bean 的作用域,以决定这个 bean 是单实例的还是多实例的。Scope 属性有四个参数,具体的使用可以看下图:
1、单实例 Bean 公告
默认情况下,Spring 只为每个在 IOC 容器里公告的 bean 创立唯逐个个实例,整个 IOC 容器范围内都能共享该实例:所有后续的 getBean()调用和 bean 引用都将返回这个唯一的 bean 实例。该作用域被称为 singleton,它是所有 bean 的默认作用域。也就是单实例。
为了验证这一说法,我们在 IOC 中创立一个单实例的 bean,并且获取该 bean 对象进行比照:
<!-- singleton单实例bean 1、在容器创立时被创立 2、只有一个实例 --><bean id="book02" class="com.spring.beans.Book" scope="singleton"></bean>
测试获取到的单实例 bean 能否是同一个:
@Testpublic void test09() { // 单实例创立时创立的两个bean相等 Book book03 = (Book)iocContext3.getBean("book02"); Book book04 = (Book)iocContext3.getBean("book02"); System.out.println(book03==book04);}
得到的结果是 true
2、多实例 Bean 公告
而既然存在单实例,那么就肯定存在多实例。我们可以为 bean 对象的 scope 属性设置 prototype 参数,以表示该实例是多实例的,同时获取 IOC 容器中的多实例 bean,再将获取到的多实例 bean 进行比照
<!-- prototype多实例bean1、在容器创立时不会被创立,2、只有在被调用的时候才会被创立3、可以存在多个实例 --><bean id="book01" class="com.spring.beans.Book" scope="prototype"></bean>
测试获取到的多实例 bean 能否是同一个:
@Testpublic void test09() { // 多实例创立时,创立的两个bean对象不相等 Book book01 = (Book)iocContext3.getBean("book01"); Book book02 = (Book)iocContext3.getBean("book01"); System.out.println(book01==book02);}
得到的结果是 false
这就说明了,通过多实例创立的 bean 对象是各不相同的。
在这里需要注意:
同时关于单实例和多实例 bean 的创立也有不同,当 bean 的作用域为单例时,Spring 会在 IOC 容器对象创立时就创立 bean 的对象实例。而当 bean 的作用域为 prototype 时,IOC 容器在获取 bean 的实例时创立 bean 的实例对象。
二、Bean 的生命周期
1、bean 的初始和销毁
其实我们在 IOC 中创立的每一个 bean 对象都是有其特定的生命周期的,在 Spring 的 IOC 容器中可以管理 bean 的生命周期,Spring 允许在 bean 生命周期内特定的时间点执行指定的任务。如在 bean 初始化时执行的方法和 bean 被销毁时执行的方法。
Spring IOC 容器对 bean 的生命周期进行管理的过程可以分为六步:
1. 通过构造器或者工厂方法创立 bean 实例
2. 为 bean 的属性设置值和对其余 bean 的引用
3. 调用 bean 的初始化方法
4. bean 可以正常使用
5. 当容器关闭时,调用 bean 的销毁方法
那么关于 bean 的初始和销毁时执行的方法又该如何公告呢?
首先我们应该在 bean 类内部增加初始和销毁时执行的方法。如下面这个 javabean:
package com.spring.beans;public class Book { private String bookName; private String author; /** * 初始化方法 * */ public void myInit() { System.out.println("book bean被创立"); } /** * 销毁时方法 * */ public void myDestory() { System.out.println("book bean被销毁"); } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } @Override public String toString() { return "Book [bookName=" + bookName + ", author=" + author + "]"; }}
这时我们在配置 bean 时,可以通过 init-method 和 destroy-method 属性为 bean 指定初始化和销毁方法
<!-- 设置bean的生命周期destory-method:结束调用的方法init-method:起始时调用的方法 --><bean id="book01" class="com.spring.beans.Book" destroy-method="myDestory" init-method="myInit"></bean>
这样当我们在通过 IOC 容器创立和销毁 bean 对象时就会执行相应的方法
但是这里还是有一点需要注意:
我们上面说了,单实例的 bean 和多实例的 bean 的创立时间是不同的,那么他们的初始方法和销毁方法的执行时间就稍稍有不同。
单实例下 bean 的生命周期
容器启动——>初始化方法——>(容器关闭)销毁方法
多实例下 bean 的生命周期
容器启动——>调用 bean——>初始化方法——>容器关闭(销毁方法不执行)
2、bean 的后置解决器
什么是 bean 的后置解决器?bean 后置解决器允许在调用初始化方法前后对 bean 进行额外的解决
bean 后置解决器对 IOC 容器里的所有 bean 实例逐一解决,而非单一实例。
其典型应用是:检查 bean 属性的正确性或者根据特定的标准更改 bean 的属性。
bean 后置解决器使用时需要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor。
在初始化方法被调用前后,Spring 将把每个 bean 实例分别传递给上述接口的以下两个方法:
postProcessBeforeInitialization(Object, String)调用前
postProcessAfterInitialization(Object, String)调用后
如下是一个实现在该接口的后置解决器:
package com.spring.beans;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;/** * 测试bean的后置解决器 * 在这里要注意一点是为了出现bean和beanName,而不是arg0、arg1,需要绑定相应的源码jar包 * */public class MyBeanPostProcessor implements BeanPostProcessor{ /** * postProcessBeforeInitialization * 初始化方法执行前执行 * Object bean * String beanName xml容器中定义的bean名称 * */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("【"+ beanName+"】初始化方法执行前..."); return bean; } /** * postProcessAfterInitialization * 初始化方法执行后执行 * Object bean * String beanName xml容器中定义的bean名称 * */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("【"+ beanName+"】初始化方法执行后..."); return bean; }}
将该后置解决器加入到 IOC 容器中:
<!-- 测试bean的后置解决器 --><bean id="beanPostProcessor" class="com.spring.beans.MyBeanPostProcessor"></bean>
因为现在我们的 bean 对象是单实例的,所以容器运行时就会直接创立 bean 对象,同时也会执行该 bean 的后置解决器方法和初始化方法,在容器被销毁时又会执行销毁方法。我们测试如下:
//*************************bean生命周期*****************// 因为ApplicationContext是一个顶层接口,里面没有销毁方法close,所以需要使用它的子接口进行接收 ConfigurableApplicationContext iocContext01 = new ClassPathXmlApplicationContext("ioc1.xml"); @Test public void test01() { iocContext01.getBean("book01"); iocContext01.close(); }
运行结果:
总结一下后置解决器的执行过程:
1. 通过构造器或者工厂方法创立 bean 实例
2. 为 bean 的属性设置值和对其余 bean 的引用
3. 将 bean 实例传递给 bean 后置解决器的**
postProcessBeforeInitialization()**方法
4. 调用 bean 的初始化方法
5. 将 bean 实例传递给 bean 后置解决器的**
postProcessAfterInitialization()**方法
6. bean 可以使用了
7. 当容器关闭时调用 bean 的销毁方法
所以增加 bean 后置解决器后 bean 的生命周期为:
容器启动——后置解决器的 before…——>初始化方法——>后置解决器的 after…———>(容器关闭)销毁方法
作者:华为云开发者社区
链接:https://juejin.cn/post/6986520115978174501
来源:掘金
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 详解 Spring 中 Bean 的作用域与生命周期