Spring中Bean的作用域与生命周期详解

目录

  • 一、Bean的作用域
    • 1、单实例Bean声明
    • 2、多实例Bean声明
  • 二、Bean的生命周期
    • 1、bean的初始和销毁
    • 2、bean的后置处理器
  • 总结
    【Spring中Bean的作用域与生命周期详解】
    一、Bean的作用域 首先我们来讲一下有关于bean的作用域,
    一般情况下,我们书写在IOC容器中的配置信息,会在我们的IOC容器运行时被创建,这就导致我们通过IOC容器获取到bean对象的时候,往往都是获取到了单实例的Bean对象,
    这样就意味着无论我们使用多少个getBean()方法,获取到的同一个JavaBean都是同一个对象,这就是单实例Bean,整个项目都会共享这一个bean对象。
    在Spring中,可以在元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。Scope属性有四个参数,具体的使用可以看下图:
    Spring中Bean的作用域与生命周期详解
    文章图片


    1、单实例Bean声明
    默认情况下,Spring只为每个在IOC容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。也就是单实例。
    为了验证这一说法,我们在IOC中创建一个单实例的bean,并且获取该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进行对比,

    测试获取到的多实例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的生命周期进行管理的过程可以分为六步:
    • 通过构造器或工厂方法创建bean实例
    • 为bean的属性设置值和对其他bean的引用
    • 调用bean的初始化方法
    • bean可以正常使用
    • 当容器关闭时,调用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指定初始化和销毁方法,

    这样当我们在通过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 stubSystem.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 stubSystem.out.println("【"+ beanName+"】初始化方法执行后..."); return bean; }}

    将该后置处理器加入到IOC容器中:

    由于现在我们的bean对象是单实例的,所以容器运行时就会直接创建bean对象,同时也会执行该bean的后置处理器方法和初始化方法,在容器被销毁时又会执行销毁方法。我们测试如下:
    //*************************bean生命周期*****************// 由于ApplicationContext是一个顶层接口,里面没有销毁方法close,所以需要使用它的子接口进行接收 ConfigurableApplicationContext iocContext01 = new ClassPathXmlApplicationContext("ioc1.xml"); @Test public void test01() {iocContext01.getBean("book01"); iocContext01.close(); }

    运行结果:
    Spring中Bean的作用域与生命周期详解
    文章图片

    Spring中Bean的作用域与生命周期详解
    文章图片

    总结一下后置处理器的执行过程:
    通过构造器或工厂方法创建bean实例为bean的属性设置值和对其他bean的引用将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法调用bean的初始化方法将bean实例传递给bean后置处理器的postProcessAfterInitialization()方法bean可以使用了当容器关闭时调用bean的销毁方法
    所以添加bean后置处理器后bean的生命周期为:
    容器启动——后置处理器的before...——>初始化方法——>后置处理器的after...———>(容器关闭)销毁方法

    总结 本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

      推荐阅读