探索InitializingBean:Spring框架中的隐藏宝藏

🌈 个人主页:danci_
🔥 系列专栏:《设计模式》《MYSQL》
💪🏻 制定明确可量化的目标,坚持默默的做事。
✨欢迎加入探索MYSQL索引数据结构之旅✨
👋 Spring框架的浩瀚海洋中,InitializingBean如同一颗闪闪发光的珍珠,等待被你发现。这一隐藏的宝藏,能够让你的Spring应用在初始化时更灵活、可控。本篇文章将带你深入探索InitializingBean的奥秘,揭示其在Spring生命周期中的重要作用,让你的开发之路更加顺畅高效。准备好开启这段奇妙的探索之旅了吗?让我们一起揭开InitializingBean的神秘面纱吧!
目录
一、环境
二、示例
2.1、说明
三、执行过程
3.1 源码解析
一、环境
- jdk: 1.8
- spring-boot: 2.7.1
二、示例
@Component
public class TestInit implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("调用TestInit.afterPropertiesSet方法");}
}
运行结果:

2.1、说明
- springboot提供InitializingBean接口,用户可以实现之来自定义初始化操作
- 实现InitializingBean接口重写afterPropertiesSet方法并注册到spring容器中,创建实例后即可触发执行自定义初始化操作
三、执行过程
一直很好奇和想弄清楚什么时候调扩展点afterPropertiesSet()方法呢?用什么方式调用?
为满足好奇,启动一个简单springboot项目跟踪源码执行过程如下:
3.1 源码解析
1. Springboot项目启动入口SpringApplication.run
public ConfigurableApplicationContext run(String... args) {// 记录启动开始时间long startTime = System.nanoTime();DefaultBootstrapContext bootstrapContext = createBootstrapContext();// 准备ApplicationContextConfigurableApplicationContext context = null;configureHeadlessProperty();// 从spring.factories 中获取监听器SpringApplicationRunListeners listeners = getRunListeners(args);// 发布事件listeners.starting(bootstrapContext, this.mainApplicationClass);try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 环境参数ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置设置进系统参数configureIgnoreBeanInfo(environment);// 输出bannerBanner printedBanner = printBanner(environment);// 创建applicationContext IOC容器context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备上下文IOC容器,设置了一系列的属性值prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 308行,启动spring容器refreshContext(context);// 刷新后的处理afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 发布事件listeners.started(context, timeTakenToStartup);// 调用 runner,实现了 ApplicationRunner或CommandLineRunner 的接口callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}
这里关注调refreshContext(context)来启动容器
2. SpringApplication.refreshContext启动容器
protected void refresh(ConfigurableApplicationContext applicationContext) {// 734行applicationContext.refresh();}
然后调AbstractApplicationContext.refresh()来启动Spring容器
3. AbstractApplicationContext.refresh()启动Spring容器
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 启动容器前准备。启动时间、状态和环境等prepareRefresh();// 告诉子类刷新内部bean工厂ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 准备在上下文中使用bean工厂prepareBeanFactory(beanFactory);try {// 允许在上下文子类中对bean工厂进行后处理。postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// 调用在上下文中注册为bean的工厂处理器invokeBeanFactoryPostProcessors(beanFactory);// 注册拦截bean创建的bean处理器。registerBeanPostProcessors(beanFactory);beanPostProcess.end();// 为此上下文初始化消息源。initMessageSource();// 初始化事件广播器initApplicationEventMulticaster();// 初始化特定上下文子类中的其他特殊bean。onRefresh();// 注册事件监听器registerListeners();// 583行,实例化所有剩余的(非lazy-init)单例finishBeanFactoryInitialization(beanFactory);// 完成启动操作finishRefresh();}catch (BeansException ex) {...}finally {resetCommonCaches();contextRefresh.end();}}
}
列出了Spring容器启动的整个过程。本例关注InitializingBean扩展点,其它内容不详细解读。 实例化所有剩余的(非lazy-init)单例 finishBeanFactoryInitialization(beanFactory);
4. AbstractApplicationContext.finishBeanFactoryInitialization(...)初始化(非lazy-init)单例
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {...// 918行,实例化所有剩余的(非lazy-init)单例。beanFactory.preInstantiateSingletons();
}
调bean工厂类的preInstantiateSingletons方法来实例化bean
5. ConfigurableListableBeanFactory.preInstantiateSingletons()实例化bean
@Override
public void preInstantiateSingletons() throws BeansException {...// 955行,获取beangetBean(beanName);...
}
这里由调父父类AbstractBeanFactory.getBean来获取bean
6.AbstractBeanFactory.getBean(beanName)获取bean
public Object getBean(String name) throws BeansException {// 208行return doGetBean(name, null, null, false);
}
然后调本类doGetBean(...)方法获取bean
7. AbstractBeanFactory.doGetBean获取bean
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {...// 332行,创建bean实例if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {...}});...}...}return adaptBeanInstance(name, beanInstance, requiredType);
}
然后调子类的createBean来创建实例
8.AbstractAutowireCapableBeanFactory.createBean(...)创建实例
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {...// 542行doCreateBean(beanName, mbdToUse, args);...
}
调本类doCreateBean
9.AbstractAutowireCapableBeanFactory.doCreateBean(...)执行创建bean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {...// 实例化 Bean// 解决循环依赖问题, 是否允许循环依赖 等...// 属性装配, 即自动注入populateBean(beanName, mbd, instanceWrapper);// 620行,应用工厂回调以及初始化方法和bean后处理程序。// 例如init-method、InitializingBean 接口、BeanPostProcessor 接口exposedObject = initializeBean(beanName, exposedObject, mbd);...
}
10. AbstractAutowireCapableBeanFactory.initializeBean处理初始化完成处理
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {...// 方法回调invokeInitMethods(beanName, wrappedBean, mbd);...
}
11. AbstractAutowireCapableBeanFactory.invokeInitMethods实例的方法回调处理
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean);// 判断为InitializingBean的实现类,且重写afterPropertiesSet方法,则调afterPropertiesSet方法if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {...((InitializingBean) bean).afterPropertiesSet();...}...
}
到此,探索InitializingBean已完。
ps: 以上是研读源码加上翻阅许多文献理解的总结,如有错误或不足的地方,欢迎指出,欢迎留言交流。我会继续努力学习和分享更多有干货的内容。
相关文章:
探索InitializingBean:Spring框架中的隐藏宝藏
🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》《MYSQL》 💪🏻 制定明确可量化的目标,坚持默默的做事。 ✨欢迎加入探索MYSQL索引数据结构之旅✨ 👋 Spring框架的浩瀚海洋中&#x…...
JVM专题之垃圾收集算法
标记清除算法 第一步:标记 (找出内存中需要回收的对象,并且把它们标记出来) 第二步:清除 (清除掉被标记需要回收的对象,释放出对应的内存空间) 缺点: 标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需 要分配较大对象时,无法找到…...
2024年6月后2周重要的大语言模型论文总结:LLM进展、微调、推理和对齐
本文总结了2024年6月后两周发表的一些最重要的大语言模型论文。这些论文涵盖了塑造下一代语言模型的各种主题,从模型优化和缩放到推理、基准测试和增强性能。 LLM进展与基准 1、 BigCodeBench: Benchmarking Code Generation with Diverse Function Calls and Com…...
大数据面试题之数仓(1)
目录 介绍下数据仓库 数仓的基本原理 数仓架构 数据仓库分层(层级划分),每层做什么?分层的好处? 数据分层是根据什么? 数仓分层的原则与思路 知道数仓建模常用模型吗?区别、优缺点? 星型模型和雪花模型的区别?应用场景?优劣对比 数仓建模有哪些方式…...
[机器学习]-4 Transformer介绍和ChatGPT本质
Transformer Transformer是由Vaswani等人在2017年提出的一种深度学习模型架构,最初用于自然语言处理(NLP)任务,特别是机器翻译。Transformer通过自注意机制和完全基于注意力的架构,核心思想是通过注意力来捕捉输入序列…...
基于深度学习的电力分配
基于深度学习的电力分配是一项利用深度学习算法优化电力系统中的电力资源分配、负荷预测、故障检测和系统管理的技术。该技术旨在提高电力系统的运行效率、稳定性和可靠性。以下是关于这一领域的系统介绍: 1. 任务和目标 电力分配的主要任务是优化电力系统中的电力…...
飞书 API 2-4:如何使用 API 将数据写入数据表
一、引入 上一篇创建好数据表之后,接下来就是写入数据和对数据的处理。 本文主要探讨数据的插入、更新和删除操作。所有的操作都是基于上一篇(飞书 API 2-4)创建的数据表进行操作。上面最终的数据表只有 2 个字段:序号和邮箱。序…...
系统设计题-日活月活统计
一、题目描述 根据访问日志统计接口的日活和月活。日志格式为 yyyy-mm-dd|clientIP|url|result 其中yyyy-mm-dd代表年月日,一个日志文件中时间跨度保证都在同一个月内,但不保证每行是按照日期顺序。 clientIP为合法的点分十进制ipv4地址(1.1.1.1和1.01.…...
在CentOS7云服务器下搭建MySQL网络服务详细教程
目录 0.说明 1.卸载不要的环境 1.1查看当前环境存在的服务mysql或者mariadb 1.2卸载不要的环境 1.2.1先关闭相关的服务 1.2.2查询曾经下载的安装包 1.2.3卸载安装包 1.2.4检查是否卸载干净 2.配置MySQLyum源 2.1获取mysql关外yum源 2.2 查看当前系统结合系统配置yum…...
【数据结构与算法】快速排序霍尔版
💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《数据结构与算法》 期待您的关注 ...
无人机5公里WiFi低延迟图传模组,抗干扰、长距离、低延迟,飞睿智能无线通信新标杆
在科技日新月异的今天,我们见证了无数通信技术的飞跃。从开始的电报、电话,到如今的4G、5G网络,再到WiFi的广泛应用,每一次技术的革新都极大地改变了人们的生活方式。飞睿智能5公里WiFi低延迟图传模组,它以其独特的优势…...
Kappa架构
1.Kappa架构介绍 Kappa架构由Jay Kreps提出,不同于Lambda同时计算和批计算并合并视图,Kappa只会通过流计算一条的数据链路计算并产生视图。Kappa同样采用了重新处理事件的原则,对于历史数据分析类的需求,Kappa要求数据的长期存储能…...
护网在即,助力安服仔漏洞扫描~
整合了个漏扫系统,安服仔必备~ 使用场景 网前布防,漏洞扫描,资产梳理 使用方法: 启动虚拟机后运行命令: ./StartSystemScript.sh 输入密码attack 启动完成后浏览器打开网站: http://IP:5000 相关账户…...
3C电子制造行业MES系统,提高企业生产效率
随着科技的不断进步,3C电子制造行业正迎来传统工厂向数字化工厂转型的阶段。在这场变革中,MES系统发挥着重要的作用,成为了企业变革的“智慧大脑”,引领着生产流程的优化和升级。 那么,MES系统究竟有哪些功能…...
C++ 多态和虚函数
参考C:多态 详解_c多态-CSDN博客 C多态——虚函数_c的a* a new b()是什么意思-CSDN博客 一.多态的概念 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如 Student 继承了 Person。 Person 对象买票全价,…...
七月记录上半
7.5 运行mysql脚本 mysql -u root -p 数据库名 < 脚本名 7.6 使用screen在服务器后台长期运行一个程序: screen -S 窗口名:创建窗口 执行程序脚本 ctrlad:退出窗口 screen -ls :查看所有窗口 screen -r 窗口号 &#…...
Wing FTP Server
文章目录 1.Wing FTP Server简介1.1主要特点1.2使用教程 2.高级用法2.1Lua脚本,案例1 1.Wing FTP Server简介 Wing FTP Server,是一个专业的跨平台FTP服务器端,它拥有不错的速度、可靠性和一个友好的配置界面。它除了能提供FTP的基本服务功能以外&#…...
【Linux进阶】文件系统6——理解文件操作
目录 1.文件的读取 1.1.目录 1.2.文件 1.3.目录树读取 1.4.文件系统大小与磁盘读取性能 2.增添文件 2.1.数据的不一致(Inconsistent)状态 2.2.日志式文件系统(Journaling filesystem) 3.Linux文件系统的运行 4、文件的删…...
Python编译器的选择
了解如何使用一个集成开发环境(IDE)对于 Python 编程是非常重要的。IDE 提供了代码编辑、运行、调试、版本控制等多种功能,可以极大地提升开发效率。以下是一些流行的 Python IDE 和代码编辑器的介绍,以及如何开始使用它们&#x…...
Java | Leetcode Java题解之第217题存在重复元素
题目: 题解: class Solution {public boolean containsDuplicate(int[] nums) {Set<Integer> set new HashSet<Integer>();for (int x : nums) {if (!set.add(x)) {return true;}}return false;} }...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
