Spring Bean的生命周期流程

前言

Java 中的公共类称之为Java Bean,而 Spring 中的 Bean 指的是将对象的生命周期,交给Spring IoC 容器来管理的对象。所以 Spring 中的 Bean 对象在使用时,无需通过 new 来创建对象,只需要通过 DI(依赖注入),从 Spring 中取出要使用的对象即可。

在Spring框架中单实例Bean的初始化和销毁过程有这样的执行顺序:

初始化顺序:@PostConstruct → InitializingBean → init-method
销毁顺序:@PreDestroy → DisposableBean → destroy-method

在初始化Bean时,@PostConstruct注解方法会首先被执行,然后是实现InitializingBean接口的afterPropertiesSet方法,最后是init-method指定的方法。

在销毁Bean时,@PreDestroy注解方法会首先被执行,然后是实现DisposableBean接口的destroy方法,最后是destroy-method指定的方法。

简单总结一下Spring Bean生命周期的流程:

  1. 实例化(通过构造器方法);
  2. 设置Bean的属性(通过setter方法);
  3. 调用Bean的初始化方法(@PostConstruct、afterPropertiesSet方法或者init-method指定的方法);
  4. Bean可以被应用程序使用;
  5. 当容器关闭时,调用Bean的销毁方法(@PreDestroy、destroy方法或者destroy-method指定的方法)。
1.Bean生命周期

Spring 中 Bean 的生命周期是指:Bean 在 Spring(IoC)中从创建到销毁的整个过程。

 Spring 中 Bean 的生命周期主要包含以下 5 部分:

  • 实例化:为 Bean 分配内存空间;
  • 设置属性:将当前类依赖的 Bean 属性,进行注入和装配;
  • 初始化:
    • 执行各种通知;
    • 执行初始化的前置方法;
    • 执行初始化方法;
    • 执行初始化的后置方法。
  • 使用 Bean:在程序中使用 Bean 对象;
  • 销毁 Bean:将 Bean 对象进行销毁操作。

需要注意的是:“实例化”和“初始化”是两个完全不同的过程,千万不要搞混;实例化只是给 Bean 分配了内存空间,而初始化则是将程序的执行权,从系统级别转换到用户级别,并开始执行用户添加的业务代码

2.代码演示

因为 Spring Boot 是基于 Spring 创建的,所以 Bean 在 Spring 或 Spring Boot 中的行为都是一致的;接下来我们使用代码的方式在 Spring Boot 中,演示一下 Bean 的生命周期。

  • 首先,我们创建一个 Bean 对象,起名为 BeanLifecycleComponent,名称可以自己指定
@Component
public class BeanLifecycleComponent implements BeanNameAware {public void setBeanName(String s) {System.out.println("执行 BeanName 的通知方法");}@PostConstructpublic void postConstruct() {System.out.println("执行初始化方法");}public void use() {System.out.println("使用 Bean");}@PreDestroypublic void preDestroy() {System.out.println("执行销毁的方法");}
}
  • 然后我们创建一个 MyBeanPostProcessor 类,实现初始化的前置方法和初始化的后置方法
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("beanLifecycleComponent")) {System.out.println("执行初始化前置方法...");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("beanLifecycleComponent")) {System.out.println("执行初始化后置方法...");}return bean;}
}

注意:初始化的前置方法和后置方法是为所有 Bean 服务的,而非为某一个 Bean 服务的,所以这两个方法不能写在某个具体的 Bean 中,要创建一个单独的类来执行,否则(这两个方法)不会执行。

  • 最后,在 Spring Boot 的启动类中获取 Bean
@SpringBootApplication
public class SpringbootDay01Application {public static void main(String[] args) {//加载上下文环境ConfigurableApplicationContext context = SpringApplication.run(SpringbootDay01Application.class, args);// 获取BeanBeanLifecycleComponent component = context.getBean(BeanLifecycleComponent.class);// 使用Beancomponent.use();// 停止Spring Boot服务context.close();}}

上面程序的执行结果输出:

问题:能不能先执行初始化再执行设置属性呢?也就是将生命周期中的步骤 2 和步骤 3 的执行顺序交换一下? 答案是否定的。

比如以下代码的执行:

@Controller
public class UserController {@Resourceprivate UserService userService;@PostConstruct // 初始化方法public void postConstruct() {userService.sayHello();}
}

此时如果先执行步骤 2,先将 UserService 注入到当前类,再调用步骤 3 执行初始化,那么程序的执行是正常的。如果将交换步骤 2 和步骤 3 的执行顺序,那么程序执行就会报错(空指针异常),所以 Bean 的生命周期顺序必须是上面的顺序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/539842.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java设计模式】二十一、访问者模式

文章目录 1、访问者模式2、案例:宠物喂食3、总结 1、访问者模式 封装一些作用于某种容器中各个元素的操作。相关角色: 抽象访问者:定义了对每一类元素访问的行为。方法个数等于具体元素类的个数,方法形参是可访问的元素。具体访…

固态硬盘有缓存和没缓存有什么区别

固态硬盘(SSD)已经成为现代计算机的重要组成部分,它们提供了比传统机械硬盘更快的读写速度,从而显著提升了操作系统的运行速度和应用程序的加载效率。 其中,缓存(Cache)是固态硬盘中一个重要的…

留学生课设|R语言|研究方法课设

目录 INSTRUCTIONS Question 1. Understanding Quantitative Research Question 2. Inputting data into Jamovi and creating variables (using the dataset) Question 3. Outliers Question 4. Tests for mean difference Question 5. Correlation Analysis INSTRUCTIO…

idea如何使用,从激活开始

idea到期后激活使用 如何使用 点击阅读 idea分享

边缘计算与物联网的核心 —— 低功耗芯片

一、低功耗芯片 在边缘计算与物联网(IoT)中,低功耗芯片扮演了至关重要的角色,主要体现在以下几个方面: 延长设备寿命:物联网设备通常需要部署在难以更换电池或不方便进行频繁维护的环境中,比如…

【FPGA】DDR3学习笔记(二)丨从SDRAM到DDR3的IP核设计

本篇文章包含的内容 一、DDR SDRAM1.1 基本概述1.2 工作时序(以读取为例) 二、DDR2 SDRAM2.1 基本概述2.2 工作时序 三、DDR3 SDRAM3.1 基本概述3.2 硬件设计3.3 读写时序3.4 MIG IP核设计3.5 读写代码设计 开发板:正点原子的达芬奇开发板&am…

PlantUML Integration 编写短信服务类图

PlantUML Integration 写一个类图,主要功能为 1、编写一个serviceSms短信服务类; 2、需要用到短信的地方统一调用基建层的服务即可; 3、可以随意切换、增加短信厂商,不需要更改场景代码,只需要更改application.yml 里面…

【OpenCV】手写字符分割

OpenCV 是一个开源的计算机视觉(Computer Vision)与机器学习软件库,提供了多种图像处理算法与接口。在 OCR 技术中,字符分割用于提取图像中的文字信息,可以应用于车牌识别、身份证识别、文档扫描等场景。本文主要记录如…

【Flutter学习笔记】9.6 动画切换组件(AnimatedSwitcher)

参考资料:《Flutter实战第二版》9.6 动画切换组件(AnimatedSwitcher) 9.6.1 AnimatedSwitcher AnimatedSwitcher 可以同时对其新、旧子元素添加显示、隐藏动画,在需要切换新旧元素的场景广泛使用。也就是说在AnimatedSwitcher的子…

Java操作Sql语句 出现迭代死循环 (Bug排查)

目录 1. 问题所示2. 原理分析3. 解决方法4. 彩蛋1. 问题所示 Java执行Sql语句来查询一些数据的时候 虽说数据量很大,但是查询过程中一直迭代查询 截图如下所示: 2. 原理分析 至于迭代死循环,可能是不满足的条件也进入查询(本身我的数据量就很大) 主要可能引起的两个原…

Python数学建模-2.3函数(下)

2.3.2模块的导入与使用 模块在Python中是一个包含Python定义和语句的文件,通常用来组织代码,使得代码更易于管理和复用。下面,我将详细讲解Python函数中模块的使用知识。 1. 模块的导入 在Python中,你可以使用import语句来导入…

【新书推荐】29.1 32位汇编基本概念

第二十九章 32处理器体系结构 这一章我们将讲述32处理器体系结构。包括32位计算机的一些基本概念,32位处理器,程序加载执行的过程,32位计算机的硬件组成和输入输出系统。 29.1 基本概念 本节内容: ■实模式与保护模式 ■操作系…