Spring的Bean初始化过程和生命周期

news2025/1/20 18:36:06

Spring的Bean初始化过程和生命周期

  • 一、Spring创建bean的流程图
  • 二、Spring创建bean的详细流程
    • 1.加载bean信息
    • 2.实例化bean
    • 3.bean属性填充
    • 4.初始化bean
    • 5.后置操作
  • 三、bean的生命周期
  • 四、总结

Spring的核心功能有三点IOC、DI、AOP,IOC则是基础,也是Spring功能的最核心的点之一。今天一起来总结下Spring中Bean是怎么被创建出来的。

一、Spring创建bean的流程图

下图是笔者多次翻看IOC源码后总结出来的bean 创建的详细过程,借助该图可以很快的理解相关源码
在这里插入图片描述

二、Spring创建bean的详细流程

上面的流程图其实已经可以很清晰的看到bean的创建过程了,这里结合图片我们一起来详细说下这个过程,这里不贴源码,贴了源码只会让观看的人比较迷糊,若是想跟源码的可以对照上面的流程图完全能做到源码复现,bean创建的这个过程大致可以分为五步:加载bean信息,实例化bean,bean属性填充,初始化bean,后置操作,那我们就基于这五大步来看看Spring是如何创建bean的。

1.加载bean信息

被IOC注解修饰的类,或者通过xml配置的类,首先在容器启动时一refresh方法为入口,会将这些类扫描进来形成BeanDefinition信息,BeanDefinition就是包含了我们配置的一些bean的属性,比如是否单例,是否有bean依赖(DependOn),bean的名称,bean所属class的全路径等,这里存储的相当于bean的元信息,然后通过 BeanDefinitionRegistry将这些BeanDefinition加载进来后面我们就可以利用该信息了,且在Spring创建Bean的全程都需要BeanDefinition的参与,所以他很重要。

2.实例化bean

通过上面的图可以清晰看到在实例化阶段之前其实还有很多小的操作:容器会先去尝试getBean–>doGetBean–>getSingleton等操作在这些操作都拿不到对象以后才会开始着手创建对象,需要说的是getSingleton会尝试从三级缓存中依次去获取Bean,当所有缓存都获取不到时就可以确认当前bean没有被创建,然后就可以启动创建的相关动作

  • 利用BeanDefinition检查是否有依赖的bean(配置了@DependOn注解)如有,需要先加载依赖bean
  • 利用BeanDefinition检查是否单例bean,是走单例bean的创建流程,不是再判断是否是原型bean,是走原型bean创建,否则都是另一套路径创建
  • 开始实例化,调用getSingleton,此时传入的是对象工厂(ObjectFactory)的实现类,因为对象工厂是函数式接口,这里传入的其实就是createBean‘的lamda表达式
  • 将当前bean加入到正在创建bean的一个set
  • 调用对象工厂的getObject方法,因为我们再上面已经传入了对象工厂(通过lamda表达式传入)这里相当于调用刚刚的lamda表达式,调用里面的createBean方法
  • createBean去调了doCreateBean又调了createBeanInstance,在这里底层通过反射技术获取构造参数将对象创建了出来,此时的对象只是通过空参构造创建出来的对象,他并没有任何的属性。
  • 调用addSingletonFactory将实例化完成的bean加入到三级缓存,到这里实例化就算是结束了

3.bean属性填充

属性填充其实就为自身属性进行赋值的过程,根据我们的DI注解这里会先从三个缓存中获取bean,若是获取不到,则会尝试进行bean的创建,若是走到了bean的创建,则会重新走一边bean创建的整个流程,这里是递归逻辑。

  • populateBean 该方法是填充属性的入口,传入beanName和BeanDefinition
  • 从BeanDefinition中获取属性注入相关信息然后判断是名称注入还是类型注入
  • 调用getSingleton从容器中获取所需对象,若是获取不到则会重走对象创建的整个流程,拿到完整对象后将其给到当前bean的属性,到这里属性填充就结束了

4.初始化bean

属性填充完毕后并没有立即结束这个过程,还有一些其他的操作需要spring进行处理,比如aware接口的处理,postprocessor接口的处理,初始化的处理等操作其实这里主要就是处理这三个动作的

  • 判断有无实现aware接口,如有则去执行他的实现类的实现方法,所有aware接口可以参考上图中所列的三个aware接口,在spring初始化时会对他们进行是否实现的判断
  • 获取容器中所有postprocessor接口,然后开始执行他的前置方法
  • 判断有无实现初始化接口InitializingBean如有则去执行初始化方法afterPropertiesSet
  • 执行postprocessor的后置方法,通过前置和后置方法我们可以实现自定义的一些逻辑,不过需要注意的是这些前置和后置方法会作用到所有bean

5.后置操作

这里的后置操作,主要是完成一些清扫工作和适配工作,比如删除二级、三级缓存中无用的bean引用等,下面是具体操作。

  • 将bean从创建中的集合中删除
  • 将bean加入到单例池中将其从二级三级缓存中删除
  • 对对象进行一些适配操作,到这里完成了初始化的所有操作,后面就是一步步返回调用的地方了

看了这五步,不知道是不是对bean的创建过程有了清晰的认识,如果还是不够清晰可以根据第一部分的流程图走下代码,代码走两遍其实就会比较清晰了。

三、bean的生命周期

bean的生命周期其实就是从创建到销毁,上面创建已经说完了,其实只差销毁这一步了。bean销毁发生在容器关闭时对单例bean进行清除操作。在Spring中我们通常有三种方式定义bean销毁时的逻辑

  • 1.通过PreDestroy注解修饰方法
    Bean销毁时会检查有无该注解修饰的方法,如有,会对该注解修饰的方法进行执行
  • 2.通过指定destroy-method方法
    在使用xml对bean进行注入时,我们可以指定init-method方法,也可以指定destroy-method方法,同样的使用Bean注解时也是支持这两个属性的,Spring容器关闭时会寻找当前bean有无指定destroy-method,如有则会进行执行
  • 3.实现DisposableBean接口
    实现该接口重写他的destroy方法,同样的Spring容器关闭时也会检查有无实现该接口,如有实现也会执行这里的销毁方法

下面是对于三种销毁方式的测试代码
第一段是自定义启动Spring容器,给容器注册钩子,这样当我们关闭Spring容器时会自动调用我们的销毁方法

public class AppStartClass {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(yuCloseSpring.class);
        annotationConfigApplicationContext.start();
        annotationConfigApplicationContext.registerShutdownHook();
    }

这一段是测试代码了,分别使用三种方式写了销毁方法

public class MyDisposableBean  implements DisposableBean{


    @Override
    public void destroy() throws Exception {
        System.out.println("执行DisposableBean的销毁方法");

    }

    public void test(){
        System.out.println("执行destroy-method销毁方法");
    }

    @PreDestroy
    public void testPreDestroy(){
        System.out.println("执行PreDestroy注解修饰的销毁方法");
    }

}
@Configuration
class yuCloseSpring{

    @Bean(destroyMethod = "test")
    public MyDisposableBean getMyDisposableBean(){
        return  new MyDisposableBean();
    }
}

下面是启动main方法后的执行截图,可以清晰的看到三种销毁方法都是正常执行的,且他们执行顺序是固定的,即:PreDestroy–>DisposableBean–>destroy-method。
在这里插入图片描述
到这里其实bean整个生命周期就算是彻底结束了。

四、总结

这篇主要总结Spring中bean的创建过程,主要分为 加载bean信息–>实例化bean–>属性填充–>初始化阶段–>后置处理等步骤,且每个步骤Spring做的事情都很多,这块源码还是很值得我们都去看一看的。而Spring中Bean的声明周期其实就是创建到使用到销毁,使用应该没啥需要说的,销毁在第三部分也正常介绍了三种销毁的方式。希望这一篇可以对路过的你有所帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python+Requests模拟发送post请求

模拟发送post请求 发送post请求的基础知识dumps和loads 代码示例: # 发送post请求 import requests,json # 发送post请求的基础知识dumps和loads str_dict {name:xiaoming,age:20,sex:男} print(type(str_dict)) str1 json.dumps(str_dict) # 1,json.dumps 是把…

git 本地新建并提交上传仓库

初始化步骤基本解释 新建readme touch README.md 初始化仓库 git init 添加仓库下所有文件 git add . 提交 备注到本地 git commit -m "备注" 链接远程git库 git remote add origin 新建库ssh链接 上传代码 git push -u origin master 初始化操作步骤 touch README.…

【Ubuntu】Ubuntu20基础配置+go开发配置

这里写自定义目录标题1 基础配置1.1 安装ifconfig网络管理工具1.2 初始化root密码1.3 换镜像源1.4 关闭息屏休眠1.5 关闭自动更新2 开发环境2.1 go2.1.1 建立软件目录并安装软件2.1.2 建立go工作目录2.1.3 配置环境变量2.2 mysql2.2.1 安装2.2.2 建立对外用户并更改密码2.2.3 修…

江苏三年制专转本法学类考纲配套课程网课题库

江苏三年制专转本法学类考纲配套课程网课题库1、江苏专转本的考试科目都有哪些? 2022年开始江苏专转本成绩主要由语文/数学英语/日语专业课三科的成绩构成,满分500分。分别给大家解释一下 语文/数学:满分150分(文科考语文&#xf…

[源码解析]socket系统调用上

文章目录socket函数API内核源码sock_createinet_createsock_allocsock_map_fd相关数据结构本文将以socket函数为例,分析它在Linux5.12.10内核中的实现,先观此图,宏观上把握它在内核中的函数调用关系:socket函数API socket 函数原…

王小川,才是深「爱」李彦宏的那个人?

在推出中国首个类ChatGPT产品「文心一言」后,李彦宏在接受专访时断言,中国基本不会再出一个OpenAI了,「创业公司重新做一个ChatGPT其实没有多大意义,基于大语言模型开发应用机会很大,没有必要再重新发明一遍轮子。」 听…

【AI理论学习】深入理解扩散模型:Diffusion Models(DDPM)(理论篇)

深入理解扩散模型:Diffusion Models引言扩散模型的原理扩散过程反向过程优化目标模型设计代码实现Stable Diffusion、DALL-E、Imagen背后共同的套路Stable DiffusionDALL-E seriesImagenText encoderDecoder什么是FID(Frechet Inception Distance&#x…

uni-app--》如何实现网上购物小程序(上)?

🏍️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名在校大学生 🛵个人主页:亦世凡华、 🛺系列专栏:uni-app 🚲座右铭:人生亦可燃烧,亦可腐败&#xf…

YOLOv8源码逐行解读(yolov8.yaml)(更新中)

本人也是刚接触YOLO不久的菜鸟一个,写博客主要是记录自己的学习过程,如果有写的不对的地方欢迎大家批评指正! yolov8.yaml 官方下载地址:https://github.com/ultralytics/ultralytics/tree/main/ultralytics/models/v8 # Ultral…

工业机器人三大主流行业浮动去毛刺应用深度详解

工业机器人是一种能够自动执行各种工业任务的机器人,它的使用不仅能将工人从繁重或有害的体力劳动中解放出来,解决当前劳动力短缺问题,而且能够提高生产效率和产品质量,增强企业整体竞争力,被广泛地应用于工业各个生产…

软件测试岗,4 轮面试成功拿下字节 Offer..........

一共经历了四轮面试:技术4面+HR面。 特整理出所涉及的全部知识点,并复盘了完整面试题及答案,分享给大家,希望能够帮到一些计划面试字节的朋友。 一、测试基础理论类 怎么编写案例?软件测试的两种方法测试结束的标准…

SpringBoot解析指定Yaml配置文件

再来个文章目录 文章目录前言1、自定义配置文件2、配置对象类3、YamlPropertiesSourceFactory下面还有投票,帮忙投个票👍 前言 最近在看某个开源项目代码并准备参与其中,代码过了一遍后发现多个自定义的配置文件用来装载业务配置代替数据库…

打造最小VR头显,软件开发商Bigscreen缘何跨进VR硬件市场?

今年2月,Bigscreen推出了一款非常轻薄的PC VR头显:Beyond。该头显的特点是采用两块1英寸Micro OLED屏幕(RGB Stripe排列),可带来双眼5K分辨率,28 PPD,75Hz/90Hz刷新率和90x93FOV。目前Beyond虽还…

Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核)

Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核) 文章目录Linux移植:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(4.1.15版本内核)1.出厂源码编译1 修改顶层 …

Matlab simulink上手控制仿真学习笔记3-常用模块S Function及使用案例

讲得真的十分细致!个人感觉看完前4节就差不多了。 今天记录的是S Function。 内容比较多,加个目录: S Function前置工作1.1 parameter.m1.2 plant.mfunction [sys,x0,str,ts,simStateCompliance] plant(t,x,u,flag,pa)function [sys,x0,str…

三电技术(电池(BMS)、电驱(MCU)、电控(VCU))

三电技术 1、概述 三电技术不仅是新能源汽车的核心技术,也是基础性技术。 三电是指电池,电驱(电机),电控,简称 BMC。 2、电池 为了区分新能源汽车上的低压电池将其称为动力电池,“动力电池“也是行业术语。动力电…

毫无废话,四个小案例手把手教你Vue2基础轻松入门_学习笔记

四个小案例手把手教你Vue2基础轻松入门_学习笔记 本文将通过四个小案例介绍Vue2学习 根据 黑马程序员vue前端基础教程-4个小时带你快速入门vue 教程。 因教程中的网络项目和综合项目难度不高,且内容仅为综合使用,本笔记不另介绍。 * 源自教程&#xff0c…

【Linux】网络编程之套接字 --TCP

目录🌈前言🌸1、TCP相关API🍡1.1、socket函数🍢1.2、bind函数🍧1.3、listen函数🍨1.4、accept函数🍰1.5、connect函数🌺2、TCP网络编程🍡2.1、简单TCP通信程序 -- 多进程…

【redis】验证redis是否正常运行以及报错解决方案

Redis 出现 “(error) NOAUTH Authentication required.” 错误,意味着客户端尝试向 Redis 服务器发送命令,但未提供身份验证或提供的身份验证信息不正确。这通常是由于 Redis 实例开启了密码认证机制导致的。 为了解决该问题,可以尝试以下…

代码随想录算法训练营第六天|242 有效的字母异位词 349 两个数组的交集 202 快乐数 1 两数之和

文章目录哈希表242 有效的字母异位词思路代码总结349 两个数组的交集思路代码总结202 快乐数思路代码总结1 两数之和思路代码总结哈希表 哈希碰撞:拉链法(链表)线性探测法(顺序向后) std::unordered_map, std::unorde…