深度解析 Spring 源码:探寻Bean的生命周期

在这里插入图片描述

文章目录

    • 一、 Bean生命周期概述
    • 二、Bean生命周期流程图
    • 三、Bean生命周期验证
      • 3.1 代码案例
      • 3.2 执行结果
    • 四、Bean生命周期源码
      • 4.1 setBeanName()
      • 4.2 setBeanFactory()
      • 4.3 setApplicationContext()
      • 4.4 postProcessBeforeInitialization()
      • 4.5 afterPropertiesSet()
      • 4.6 postProcessAfterInitialization()
      • 4.7 destroy()

一、 Bean生命周期概述

Bean的生命周期包括了定义、实例化、初始化和销毁四个关键阶段,Spring框架在每个阶段都提供了钩子方法,允许开发者在特定的时机执行自定义的逻辑,从而实现对Bean生命周期的定制化管理。

  1. Bean的定义阶段: 在这个阶段,Spring会解析Bean的定义,包括从配置文件中读取Bean的元数据,例如类名、属性值、依赖关系等。这个阶段的主要目标是将Bean的定义加载到Spring的应用上下文中。
  2. Bean的实例化阶段: 一旦Bean的定义加载到容器中,Spring会根据这些定义创建Bean的实例。这可能涉及到通过构造函数或工厂方法创建实例,并将依赖项注入到Bean中。在这个阶段,Spring会创建Bean的原始对象,并将其放入容器中。
  3. Bean的初始化阶段: 在这个阶段,Spring会对Bean进行初始化。这包括执行任何在Bean实例化之后需要执行的定制逻辑,例如调用初始化方法、应用BeanPostProcessors等。这个阶段是在Bean实例创建完成后、在将Bean实例提供给应用程序之前执行的。
  4. Bean的销毁阶段: 最后一个阶段是Bean的销毁。在容器关闭或者特定的销毁时机触发时,Spring会调用Bean的销毁方法,执行清理工作,例如释放资源、关闭连接等。这个阶段是确保Bean在不再需要时能够正确地释放资源。

二、Bean生命周期流程图

在这里插入图片描述

Bean的生命周期执行步骤

  1. Bean实例化:当Spring容器启动时,它会创建Bean的实例。这通常是通过调用Bean的构造函数来完成的。
  2. Bean属性注入:在Bean实例化之后,Spring会进行属性注入。这是将外部数据或配置信息设置到Bean的属性中的过程。
  3. BeanNameAware接口的setBeanName方法调用:如果Bean实现了BeanNameAware接口,那么在Bean被初始化之前,Spring会调用其setBeanName方法,并传递给它一个字符串,表示Bean的名称。
  4. BeanFactoryAware接口的setBeanFactory方法调用:如果Bean实现了BeanFactoryAware接口,那么在Bean被初始化之前,Spring会调用其setBeanFactory方法,并传递给它一个BeanFactory对象,以便Bean可以访问工厂的其他Bean。(同理~调用ApplicationContextAware接口的setApplicationContext()方法)
  5. BeanPostProcessor接口的初始化之前方法调用:在Bean的属性注入之后,但在初始化之前,Spring将调用BeanPostProcessor接口的postProcessBeforeInitialization方法来对bean执行一些额外的操作。
  6. InitializingBean接口的afterPropertiesSet方法调用:如果Bean实现了InitializingBean接口,并且在它的afterPropertiesSet方法中被调用之前,Spring会尝试对其进行属性注入。
  7. BeanPostProcessor接口的初始化之前方法调用:在Bean的属性注入之后,但在初始化之后,Spring将调用BeanPostProcessor接口的postProcessAfterInitialization方法来对bean执行一些额外的操作。
  8. Bean正常使用:在Bean完成所有必要的初始化之后,它就可以被使用了。这时,应用程序可以通过依赖注入或其他方式获取Bean的引用,并进行相应的操作。
  9. DisposableBean接口的destroy方法调用:当Spring容器关闭时,它会销毁Bean。如果Bean实现了DisposableBean接口,那么在Bean被销毁之前,Spring会调用其destroy方法。
  10. 自定义销毁方法调用:除了上面的标准方法外,还可以为Bean定义自定义的销毁方法,并在容器关闭时自动调用。

三、Bean生命周期验证

本文使用 Spring Framework 的注解来描述一个完整的 Bean 生命周期。Bean 的完整生命周期,包括创建、初始化、使用和销毁。

3.1 代码案例

演示 Bean 的完整生命周期Demo

  1. 配置类AppConfig 类使用 @Configuration 注解定义 Spring 配置类,并声明了一个 Bean。
package com.example.springdemo.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyBean myBeanDemo() {
        return new MyBean();
    }
}
  1. Bean 类MyBean 类是我们要管理的 Bean。它包含一个 @PostConstruct 注解的 init() 方法,该方法将在 Bean 初始化后立即执行。此外,它还包含一个 @PreDestroy 注解的 destroy() 方法,该方法将在 Bean 销毁前执行。
package com.example.springdemo.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class MyBean implements BeanNameAware, BeanFactoryAware,
        ApplicationContextAware, InitializingBean, DisposableBean {
    public MyBean() {
        System.out.println("Bean 构造函数调用...");
    }

    @PostConstruct
    public void init() {
        System.out.println("Bean 初始化...");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Bean 销毁...");
    }

    public void performTask() {
        System.out.println("Bean 正在执行任务...");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Bean 获得所在BeanFactory引用...");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("Bean 名称...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean 属性设置之后,自定义的初始化...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("Bean 获得所在ApplicationContext引用...");
    }
}

  1. Main 类Main 类是主程序入口,创建 Spring 应用程序上下文,获取 Bean 实例,并在使用完 Bean 后关闭上下文。
package com.example.springdemo;

import com.example.springdemo.bean.AppConfig;
import com.example.springdemo.bean.MyBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@SpringBootApplication
public class SpringDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringDemoApplication.class, args);
		// 创建 Spring 应用程序上下文
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		// 获取 MyBean 实例
		MyBean bean = context.getBean(MyBean.class);

		// 使用 Bean
		bean.performTask();

		// 关闭上下文
		context.close();
	}
}

3.2 执行结果

在这里插入图片描述

四、Bean生命周期源码

需要调试运行看Bean生命周期的读者可自行尝试哈,本文主要解读部分相对重要的源码,亲测一直nextStep,根本点不完-_-,头昏眼花,哈哈哈哈我是菜鸡

4.1 setBeanName()

Bean 实现了 BeanNameAware 接口时,容器在初始化 Bean 时会调用其 setBeanName() 方法,从而允许 Bean 在初始化阶段获取自己在容器中的名字。

在这里插入图片描述

4.2 setBeanFactory()

BeanFactoryAware 接口允许一个 Bean 在初始化阶段获得对自己所在的 BeanFactory 的引用,从而可以与容器进行交互,例如动态地获取其他 Bean 实例或执行特定的逻辑。

在这里插入图片描述

4.3 setApplicationContext()

ApplicationContextAware 接口允许一个 Bean 在初始化阶段获得对自己所在的 ApplicationContext 的引用,从而可以与容器进行交互,例如动态地获取其他 Bean 实例或执行特定的逻辑。 (细心的读者发现这个视乎和前面类似,读者可看我前面的文章,有细说BeanFactory 和ApplicationContext 的区别)

在这里插入图片描述

4.4 postProcessBeforeInitialization()

BeanPostProcessor 接口定义了两个默认方法,分别用于在初始化 Bean 之前和之后对其进行一些自定义处理,但默认情况下不对 Bean 进行修改。

在这里插入图片描述

4.5 afterPropertiesSet()

InitializingBean 接口定义了一个方法 afterPropertiesSet(),用于在 Bean 的属性设置之后执行自定义的初始化逻辑。

在这里插入图片描述

4.6 postProcessAfterInitialization()

BeanPostProcessor 接口定义了两个默认方法,分别用于在初始化 Bean 之前和之后对其进行一些自定义处理,但默认情况下不对 Bean 进行修改。 (与4.4相同,只是调用的顺序不同,结合一起看哈)

在这里插入图片描述

4.7 destroy()

Bean准备就绪,可被应用程序使用,且一直驻留在应用上下文中,直到应用上下文被销毁。 DisposableBean 接口定义了一个方法 destroy(),用于在 Bean 销毁之前执行自定义的清理逻辑。

在这里插入图片描述

ps:想要了解各个方法的实现类的读者可自行解读相应的源码。

知识象烛光,能照亮一个人,也能照亮无数人

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

银行数字化转型导师坚鹏:银行数字化转型5大战略定位

银行数字化转型必须建立清晰的战略定位,可以从以下5个方面建立,使广大银行员工明白银行数字化转型的重要性。 1.国家战略落地的重要抓手 银行是中国金融体系的核心,银行是做好“科技金融、绿色金融、普惠金融、养老金融和数字金融‘五篇大文…

【c++】继承学习(二):探索 C++ 中派生类的默认机制与静态成员共享

🔥个人主页:Quitecoder 🔥专栏:c笔记仓 目录 1.派生类的默认成员函数2.继承与友元3.继承与静态成员 朋友们大家好,本篇文章我们来学习继承的第二部分 1.派生类的默认成员函数 来看下面的类: class Person…

【自留】运行一个开源项目

运行一个开源项目 首先是运行起来 1. 拿到地址 拿到你想要的项目的地址 2. 克隆 打开编辑器 VSCode ,创建一个放项目的文件夹,控制台输入以下代码克隆项目 git clone 克隆地址gitee克隆地址在这看: github上项目的话,在这…

【python的魅力】:教你如何用几行代码实现文本语音识别

文章目录 引言一、运行效果二、文本转换为语音2.1 使用pyttsx32.2 使用SAPI实现文本转换语音2.3 使用 SpeechLib实现文本转换语音 三、语音转换为文本3.1 使用 PocketSphinx实现语音转换文本 引言 语音识别技术,也被称为自动语音识别,目标是以电脑自动将…

SSM+Vue+小程序+基于微信小程序的高校学生事务管理系统

项目配合学校日常生活通知,考试等管理需要,开发学校事务管理系统,maven管理依赖,mybatis处理数据库交互 学校管理 学院管理 班级管理 年级管理 教师管理 通知公告管理 学生资料管理 待办事项管理 教务处通知管理 讲座通…

【Conda】解决无名虚拟环境问题

文章目录 问题描述:无名虚拟环境解决步骤1 添加虚拟环境目录到envs步骤2 成功命名 问题描述:无名虚拟环境 如果不指定创建目录,默认创建在C盘用户目录下,这应该是很多人不愿意的吧。 指定目录创建虚拟环境命令如下: …

vector的使用

1.构造函数 void test_vector1() {vector<int> v; //无参的构造函数vector<int> v2(10, 0);//n个value构造&#xff0c;初始化为10个0vector<int> v3(v2.begin(), v2.end());//迭代器区间初始化,可以用其他容器的区间初始化vector<int> v4(v3); //拷贝…

基于yolov8的苹果腐败检测系统,系统既支持图像检测,也支持视频和摄像实时检测(pytorch框架)【python源码+UI界面+功能源码详解】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的苹果腐败检测系统&#xff0c;系统既支持图像检测&#xff0c;也支持视频和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的苹果腐败检测系统是在pytorc…

STM32 F103C8T6学习笔记17:类IIC通信(SMBus协议)—MLX90614红外非接触温度计

今日学习配置MLX90614红外非接触温度计 与 STM32 F103C8T6 单片机的通信 文章提供测试代码讲解、完整工程下载、测试效果图 本文需要用到的大概基础知识&#xff1a;1.3寸OLED配置通信显示、IIC通信、 定时器配置使用 这里就只贴出我的 OLED驱动方面的网址链接了&#xff1a…

Golang数组与切片

文章目录 数组数组介绍数组的定义方式访问与修改数组元素遍历数组元素数组指针 切片切片介绍切片的定义方式访问与修改切片元素添加切片元素切片的拷贝遍历切片元素string的切片 数组 数组介绍 数组介绍 在Go中&#xff0c;数组是一个由固定长度的特定类型元素组成的序列&…

[Algorithm][队列][宽搜BFS][N叉树的层序遍历][二叉树的锯齿形层序遍历][二叉树最大宽度][在每个树行中找最大值]详细讲解

目录 1.N 叉树的层序遍历1.题目链接2.算法思路详解3.代码实现 2.二叉树的锯齿形层序遍历1.题目链接2.算法原理详解3.代码实现 3.二叉树最大宽度1.题目链接2.算法原理详解3.代码实现 4.在每个树行中找最大值1.题目链接2.算法原理详解3.代码实现 1.N 叉树的层序遍历 1.题目链接 …

数据结构之链表深度讲解

小伙伴们&#xff0c;大家好呀&#xff0c;上次听我讲完顺序表想必收获不少吧&#xff0c;嘿嘿&#xff0c;这篇文章你也一样可以学到很多&#xff0c;系好安全带&#xff0c;咱们要发车了。 因为有了上一次顺序表的基础&#xff0c;所以这次我们直接进入正题&#xff0c;温馨…

Activiti7 开发快速入门【2024版】

记录开发最核心的部分&#xff0c;理论结合业务实操减少废话&#xff0c;从未接触工作流快速带入开发。假设你是后端的同学学过JAVA和流程图&#xff0c;则可以继续向后看&#xff0c;否则先把基础课程书准备好先翻翻。 为什么要工作流 比起直接使用状态字段&#xff0c;工作…

【 书生·浦语大模型实战营】作业(六):Lagent AgentLego 智能体应用搭建

【 书生浦语大模型实战营】作业&#xff08;六&#xff09;&#xff1a;Lagent & AgentLego 智能体应用搭建 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方…

【机器学习】集成方法---Boosting之AdaBoost

一、Boosting的介绍 1.1 集成学习的概念 1.1.1集成学习的定义 集成学习是一种通过组合多个学习器来完成学习任务的机器学习方法。它通过将多个单一模型&#xff08;也称为“基学习器”或“弱学习器”&#xff09;的输出结果进行集成&#xff0c;以获得比单一模型更好的泛化性…

上海计算机学会2021年1月月赛C++丙组T2康托表

题目背景 康托是一名数学家&#xff0c;他证明了一个重要的定理&#xff0c;需要使用一张表&#xff1a; 这个表的规律是&#xff1a; 从上到下&#xff1a;每一行的分子依次增大&#xff1b;从左到右&#xff1a;每一列的分母依次增大。 康托以一种不重复、不遗漏的方式&am…

【深耕 Python】Quantum Computing 量子计算机(1)图像绘制基础

一、绘制静止图像 使用matplotlib库绘制函数图像y sin(pi * x): import math import matplotlib.pyplot as pltx_min -2.0 x_max 2.0N 1000x1 [] y1 []for i in range(N 1):x x_min (x_max - x_min) * i / Ny math.sin(math.pi * x)x1.append(x)y1.append(y)plt.xl…

关于继承~

继承 动物有猫、狗&#xff0c; 猫又分为加菲猫、布偶猫......&#xff1b;狗又有哈士奇、德国牧羊犬...... 我们发现&#xff0c;下一类除了拥有上一类的共性之外&#xff0c;还拥有自己的特性。 于是我们可以利用继承的方式来减少重复的代码 继承的基本语法 class A:p…

二叉树的直径

题目描述&#xff1a;给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。两节点之间路径的 长度 由它们之间边数表示。 示例 1&#xff1a; 输入&#xff1a;root […

在剪映专业版中新增字体的方法

我一开始以为剪映专业版没有繁体字&#xff0c;结果发现有一个现代繁体&#xff0c;如图所示: 但是我已经下载了字体了&#xff0c;不用就可惜了。 点击汉仪粗黑繁&#xff0c;安装。 安装之后&#xff0c;重启电脑&#xff0c;打开剪映&#xff0c;就可以搜索到这个字体了。 这…