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

简介:

 

目录

一、Bean的作用域

1、单实例Bean声明

2、多实例Bean声明

二、Bean的生命周期

1、bean的初始和销毁

2、bean的后置处理器


Hello,你好呀,我是灰小猿!一个超会写bug的程序猿!

在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我就来和大家讲一下有关Spring中bean的作用域和其生命周期。

一、Bean的作用域

首先我们来讲一下有关于bean的作用域,

一般情况下,我们书写在IOC容器中的配置信息,会在我们的IOC容器运行时被创建,这就导致我们通过IOC容器获取到bean对象的时候,往往都是获取到了单实例的Bean对象,

这样就意味着无论我们使用多少个getBean()方法,获取到的同一个JavaBean都是同一个对象,这就是单实例Bean,整个项目都会共享这一个bean对象。

在Spring中,可以在<bean>元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。Scope属性有四个参数,具体的使用可以看下图:

image.gif编辑

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>

image.gif

测试获取到的单实例bean是否是同一个:

@Test
public void test09() {
    // 单实例创建时创建的两个bean相等
    Book book03 = (Book)iocContext3.getBean("book02");
    Book book04 = (Book)iocContext3.getBean("book02");
    System.out.println(book03==book04);
}

image.gif

得到的结果是true;

2、多实例Bean声明

而既然存在单实例,那么就一定存在多实例。我们可以为bean对象的scope属性设置prototype参数,以表示该实例是多实例的,同时获取IOC容器中的多实例bean,再将获取到的多实例bean进行对比,

<!-- prototype多实例bean
1、在容器创建时不会被创建,
2、只有在被调用的时候才会被创建
3、可以存在多个实例
 -->
<bean id="book01" class="com.spring.beans.Book" scope="prototype"></bean>

image.gif

测试获取到的多实例bean是否是同一个:

@Test
public void test09() {
    // 多实例创建时,创建的两个bean对象不相等
    Book book01 = (Book)iocContext3.getBean("book01");
    Book book02 = (Book)iocContext3.getBean("book01");
    System.out.println(book01==book02);
}

image.gif

得到的结果是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 + "]";
      }
    }

    image.gif

    这时我们在配置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>

    image.gif

    这样当我们在通过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;
      }
    }

    image.gif

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

    <!-- 测试bean的后置处理器 -->
    <bean id="beanPostProcessor" class="com.spring.beans.MyBeanPostProcessor"></bean>

    image.gif

    由于现在我们的bean对象是单实例的,所以容器运行时就会直接创建bean对象,同时也会执行该bean的后置处理器方法和初始化方法,在容器被销毁时又会执行销毁方法。我们测试如下:

    //*************************bean生命周期*****************
    //  由于ApplicationContext是一个顶层接口,里面没有销毁方法close,所以需要使用它的子接口进行接收
      ConfigurableApplicationContext iocContext01 = new ClassPathXmlApplicationContext("ioc1.xml");
      @Test
      public void test01() {
        iocContext01.getBean("book01");
        iocContext01.close();
      }

    image.gif

    运行结果:

    image.gif编辑

    image.gif编辑

    总结一下后置处理器的执行过程:

      1. 通过构造器或工厂方法创建bean实例
      2. 为bean的属性设置值和对其他bean的引用
      3. 将bean实例传递给bean后置处理器的postProcessBeforeInitialization()方法
      4. 调用bean的初始化方法
      5. 将bean实例传递给bean后置处理器的postProcessAfterInitialization()方法
      6. bean可以使用了
      7. 当容器关闭时调用bean的销毁方法

      所以添加bean后置处理器后bean的生命周期为:

      容器启动——后置处理器的before...——>初始化方法——>后置处理器的after...———>(容器关闭)销毁方法

      以上就是在SpringIOC中bean的作用域和生命周期的使用教程,有问题的小伙伴可以评论区或私信提出!

      点赞收藏,以留备用!

      我是灰小猿!我们下期见!

      image.gif编辑

      目录
      相关文章
      |
      1天前
      |
      缓存 Java Spring
      实战指南:四种调整 Spring Bean 初始化顺序的方案
      本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
      实战指南:四种调整 Spring Bean 初始化顺序的方案
      |
      29天前
      |
      XML Java 数据格式
      Spring从入门到入土(bean的一些子标签及注解的使用)
      本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
      59 9
      Spring从入门到入土(bean的一些子标签及注解的使用)
      |
      2月前
      |
      缓存 安全 Java
      Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
      从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
      169 24
      Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
      |
      20天前
      |
      Java 测试技术 Windows
      咦!Spring容器里为什么没有我需要的Bean?
      【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
      |
      2月前
      |
      XML Java 数据格式
      Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
      Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
      193 18
      Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
      |
      2月前
      |
      XML Java 数据格式
      spring复习02,xml配置管理bean
      详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
      spring复习02,xml配置管理bean
      |
      29天前
      |
      Java 开发者 Spring
      Spring bean的生命周期详解!
      本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
      62 1
      |
      1月前
      |
      Java Spring
      获取spring工厂中bean对象的两种方式
      获取spring工厂中bean对象的两种方式
      27 1
      |
      1月前
      |
      Java 开发者 Spring
      Spring bean的生命周期详解!
      本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
      75 1
      |
      2月前
      |
      XML Java 数据格式
      spring复习03,注解配置管理bean
      Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
      spring复习03,注解配置管理bean